From d3049ae4227493993f3cd01594a84e9449add591 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:45:04 +0200 Subject: [PATCH 01/64] docs: test3 -> portal loop (#2897) Update links from test3 to portal loop where appropriate. --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- README.md | 6 +++--- docs/concepts/gnovm.md | 2 +- examples/gno.land/r/demo/boards/README.md | 12 ++++++------ examples/gno.land/r/gnoland/home/home.gno | 4 +--- examples/gno.land/r/gnoland/home/home_filetest.gno | 4 +--- examples/gno.land/r/gnoland/pages/page_testnets.gno | 5 +---- gno.land/cmd/gnoweb/README.md | 2 +- gnovm/README.md | 2 +- gnovm/cmd/gno/mod.go | 2 +- gnovm/pkg/gnomod/file_test.go | 6 +++--- 10 files changed, 19 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 19ac161e790..eeffc9adefc 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ If you haven't already, take a moment to check out our [website](https://gno.lan > The website is a deployment of our [gnoweb](./gno.land/cmd/gnoweb) frontend; you > can use it to check out -> [some](https://test3.gno.land/r/demo/boards) -> [example](https://test3.gno.land/r/gnoland/blog) -> [contracts](https://test3.gno.land/r/demo/users). +> [some](https://gno.land/r/demo/boards) +> [example](https://gno.land/r/gnoland/blog) +> [contracts](https://gno.land/r/demo/users). > > Use the `[source]` button in the header to inspect the program's source; use > the `[help]` button to view how you can use [`gnokey`](./gno.land/cmd/gnokey) diff --git a/docs/concepts/gnovm.md b/docs/concepts/gnovm.md index 16e43cb0d42..13e55defb71 100644 --- a/docs/concepts/gnovm.md +++ b/docs/concepts/gnovm.md @@ -8,7 +8,7 @@ GnoVM is a virtual machine that interprets Gno, a custom version of Go optimized It works with Tendermint2 and enables smarter, more modular, and transparent appchains with embedded smart-contracts. It can be adapted for use in TendermintCore, forks, and non-Cosmos blockchains. -Read the ["Intro to Gnoland"](https://test3.gno.land/r/gnoland/blog:p/intro) blogpost. +Read the ["Intro to Gnoland"](https://gno.land/r/gnoland/blog:p/intro) blogpost. This folder focuses on the VM, language, stdlibs, tests, and tools, independent of the blockchain. This enables non-web3 developers to contribute without requiring an understanding of the broader context. diff --git a/examples/gno.land/r/demo/boards/README.md b/examples/gno.land/r/demo/boards/README.md index 628bc9aa349..3aa765df25a 100644 --- a/examples/gno.land/r/demo/boards/README.md +++ b/examples/gno.land/r/demo/boards/README.md @@ -8,8 +8,8 @@ name ["gno.land/r/demo/boards"](https://gno.land/r/demo/boards/) ## Build `gnokey`, create your account, and interact with Gno. NOTE: Where you see `-remote localhost:26657` here, that flag can be replaced -with `-remote test3.gno.land:26657` if you have $GNOT on the testnet. -(To use the testnet, also replace `-chainid dev` with `-chainid test3` .) +with `-remote gno.land:26657` if you have $GNOT on the testnet. +(To use the testnet, also replace `-chainid dev` with `-chainid portal-loop` .) ### Build `gnokey` (and other tools). @@ -85,7 +85,7 @@ The `USERNAME` for posting can different than your `KEYNAME`. It is internally l ./build/gnokey maketx call -pkgpath "gno.land/r/demo/users" -func "Register" -args "" -args "USERNAME" -args "Profile description" -gas-fee "10000000ugnot" -gas-wanted "2000000" -send "200000000ugnot" -broadcast -chainid dev -remote 127.0.0.1:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/users?help&__func=Register +Interactive documentation: https://gno.land/r/demo/users?help&__func=Register ### Create a board with a smart contract call. @@ -93,7 +93,7 @@ Interactive documentation: https://test3.gno.land/r/demo/users?help&__func=Regis ./build/gnokey maketx call -pkgpath "gno.land/r/demo/boards" -func "CreateBoard" -args "BOARDNAME" -gas-fee "1000000ugnot" -gas-wanted "10000000" -broadcast -chainid dev -remote localhost:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=CreateBoard +Interactive documentation: https://gno.land/r/demo/boards?help&__func=CreateBoard Next, query for the permanent board ID by querying (you need this to create a new post): @@ -109,7 +109,7 @@ NOTE: If a board was created successfully, your SEQUENCE_NUMBER would have incre ./build/gnokey maketx call -pkgpath "gno.land/r/demo/boards" -func "CreateThread" -args BOARD_ID -args "Hello gno.land" -args "Text of the post" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid dev -remote localhost:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=CreateThread +Interactive documentation: https://gno.land/r/demo/boards?help&__func=CreateThread ### Create a comment to a post. @@ -117,7 +117,7 @@ Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=Crea ./build/gnokey maketx call -pkgpath "gno.land/r/demo/boards" -func "CreateReply" -args BOARD_ID -args "1" -args "1" -args "Nice to meet you too." -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid dev -remote localhost:26657 KEYNAME ``` -Interactive documentation: https://test3.gno.land/r/demo/boards?help&__func=CreateReply +Interactive documentation: https://gno.land/r/demo/boards?help&__func=CreateReply ```bash ./build/gnokey query "vm/qrender" -data "gno.land/r/demo/boards:BOARDNAME/1" -remote localhost:26657 diff --git a/examples/gno.land/r/gnoland/home/home.gno b/examples/gno.land/r/gnoland/home/home.gno index 921492d81b4..93f9a68f39a 100644 --- a/examples/gno.land/r/gnoland/home/home.gno +++ b/examples/gno.land/r/gnoland/home/home.gno @@ -269,9 +269,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 3](https://test3.gno.land/) (archive) -- [Testnet 2](https://test2.gno.land/) (archive) +- [Testnet 4](https://test4.gno.land/) - 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..2260dc3a409 100644 --- a/examples/gno.land/r/gnoland/home/home_filetest.gno +++ b/examples/gno.land/r/gnoland/home/home_filetest.gno @@ -56,9 +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 3](https://test3.gno.land/) (archive) -// - [Testnet 2](https://test2.gno.land/) (archive) +// - [Testnet 4](https://test4.gno.land/) // - Testnet Faucet Hub (soon) // // diff --git a/examples/gno.land/r/gnoland/pages/page_testnets.gno b/examples/gno.land/r/gnoland/pages/page_testnets.gno index 05f29a8e0f4..900ee2e3bf7 100644 --- a/examples/gno.land/r/gnoland/pages/page_testnets.gno +++ b/examples/gno.land/r/gnoland/pages/page_testnets.gno @@ -6,10 +6,7 @@ func init() { body := ` - [Portal Loop](https://docs.gno.land/concepts/portal-loop) - a rolling testnet - [staging.gno.land](https://staging.gno.land) - wiped every commit to monorepo master -- test4.gno.land (upcoming) -- _[test3.gno.land](https://test3.gno.land) (latest)_ -- _[test2.gno.land](https://test2.gno.land) (archive)_ -- _[test1.gno.land](https://test1.gno.land) (archive)_ +- _[test4.gno.land](https://test4.gno.land) (latest)_ For a list of RPC endpoints, see the [reference documentation](https://docs.gno.land/reference/rpc-endpoints). diff --git a/gno.land/cmd/gnoweb/README.md b/gno.land/cmd/gnoweb/README.md index 941d5e4f67e..6379d3f6c43 100644 --- a/gno.land/cmd/gnoweb/README.md +++ b/gno.land/cmd/gnoweb/README.md @@ -2,7 +2,7 @@ The gno.land web interface. -Live demo: https://test3.gno.land/ +Live demo: https://gno.land/ ## Install `gnoweb` diff --git a/gnovm/README.md b/gnovm/README.md index 91419746cfa..2fe4345c367 100644 --- a/gnovm/README.md +++ b/gnovm/README.md @@ -4,7 +4,7 @@ GnoVM is a virtual machine that interprets Gnolang, a custom version of Golang o It works with Tendermint2 and enables smarter, more modular, and transparent appchains with embedded smart-contracts. It can be used in TendermintCore, forks, and non-Cosmos blockchains. -Read the ["Intro to Gnoland"](https://test3.gno.land/r/gnoland/blog:p/intro) blogpost. +Read the ["Intro to Gnoland"](https://gno.land/r/gnoland/blog:p/intro) blogpost. This folder focuses on the VM, language, stdlibs, tests, and tools, independent of the blockchain. This enables non-web3 developers to contribute without requiring an understanding of the broader context. diff --git a/gnovm/cmd/gno/mod.go b/gnovm/cmd/gno/mod.go index fec1b0ab2c1..03b2bb348a8 100644 --- a/gnovm/cmd/gno/mod.go +++ b/gnovm/cmd/gno/mod.go @@ -131,7 +131,7 @@ func (c *modDownloadCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( &c.remote, "remote", - "test3.gno.land:26657", + "gno.land:26657", "remote for fetching gno modules", ) diff --git a/gnovm/pkg/gnomod/file_test.go b/gnovm/pkg/gnomod/file_test.go index 7abfe16f340..a64c2794a65 100644 --- a/gnovm/pkg/gnomod/file_test.go +++ b/gnovm/pkg/gnomod/file_test.go @@ -14,7 +14,7 @@ import ( "golang.org/x/mod/module" ) -const testRemote string = "test3.gno.land:26657" +const testRemote string = "gno.land:26657" // XXX(race condition): test with a local node so that this test is consistent with git and not with a deploy func TestFetchDeps(t *testing.T) { for _, tc := range []struct { @@ -68,7 +68,7 @@ func TestFetchDeps(t *testing.T) { "cached gno.land/p/demo/avl", }, }, { - desc: "fetch_gno.land/p/demo/blog", + desc: "fetch_gno.land/p/demo/blog6", modFile: File{ Module: &modfile.Module{ Mod: module.Version{ @@ -84,7 +84,7 @@ func TestFetchDeps(t *testing.T) { }, }, }, - requirements: []string{"avl", "blog", "ufmt"}, + requirements: []string{"avl", "blog", "ufmt", "mux"}, stdOutContains: []string{ "fetching gno.land/p/demo/blog", "fetching gno.land/p/demo/avl // indirect", From 628f965a1983697cf9b197a053e31878409924f0 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Sat, 5 Oct 2024 22:47:58 +0200 Subject: [PATCH 02/64] chore(ci): do not mark master as failing due to benchmark (#2913) --- .github/workflows/benchmark-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index ba8c11b2007..a219a49305a 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -49,7 +49,7 @@ jobs: max-items-in-chart: 100 # Show alert with commit comment on detecting possible performance regression alert-threshold: "120%" - fail-on-alert: true + fail-on-alert: false comment-on-alert: true alert-comment-cc-users: "@ajnavarro,@thehowl,@zivkovicmilos" # Enable Job Summary for PRs From e5840e2aa2ed0e0fdf2d4c43c1d3d277f0cbd47b Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:35:31 +0200 Subject: [PATCH 03/64] fix(gnoweb): fix broken link (#2926) ## Description Fixes a broken link. Closes: #2925
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [x] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- gno.land/pkg/gnoweb/views/realm_help.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gno.land/pkg/gnoweb/views/realm_help.html b/gno.land/pkg/gnoweb/views/realm_help.html index b9c8e119e7a..0a93f786c0d 100644 --- a/gno.land/pkg/gnoweb/views/realm_help.html +++ b/gno.land/pkg/gnoweb/views/realm_help.html @@ -17,7 +17,7 @@
These are the realm's exposed functions ("public smart contracts").

- My address: (see `gnokey list`)
+ My address: (see `gnokey list`)


{{ template "func_specs" . }} From 2f605805efee5b48f26fe8cef2ac69b936845ea3 Mon Sep 17 00:00:00 2001 From: Michelle <117160070+michelleellen@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:09:38 +0200 Subject: [PATCH 04/64] chore(gnoweb): update page_contribute.gno (#2922) Added the gno.land grants GH repository link to the page --- examples/gno.land/r/gnoland/pages/page_contribute.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/gnoland/pages/page_contribute.gno b/examples/gno.land/r/gnoland/pages/page_contribute.gno index 3cdef10d9dc..a4bdfabb6ef 100644 --- a/examples/gno.land/r/gnoland/pages/page_contribute.gno +++ b/examples/gno.land/r/gnoland/pages/page_contribute.gno @@ -80,7 +80,7 @@ _[3XL]_ \* | $ 32000 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. - +For more details on gno.land grants, suggested topics, and how to apply, visit our grants [repository](https://github.com/gnolang/grants). ## Join Game of Realms From 912a5dbf5c1d7118472a4f46b26bfcd7f4072856 Mon Sep 17 00:00:00 2001 From: Malek Lahbib <111009238+MalekLahbib@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:20:04 +0200 Subject: [PATCH 05/64] docs(/p/demo/json): update json package README.md (#2921) in the three examples provided in the README.md file, there's a useless import of "fmt" package.
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- examples/gno.land/p/demo/json/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/gno.land/p/demo/json/README.md b/examples/gno.land/p/demo/json/README.md index 86bc9928194..d983333d246 100644 --- a/examples/gno.land/p/demo/json/README.md +++ b/examples/gno.land/p/demo/json/README.md @@ -75,7 +75,6 @@ The converted `Node` type allows you to modify the JSON data or search and extra package main import ( - "fmt" "gno.land/p/demo/json" "gno.land/p/demo/ufmt" ) @@ -100,7 +99,6 @@ Encoding (or Marshaling) is the functionality that converts JSON data represente package main import ( - "fmt" "gno.land/p/demo/json" "gno.land/p/demo/ufmt" ) @@ -133,7 +131,6 @@ Here is an example of finding data with a specific key. For more examples, pleas package main import ( - "fmt" "gno.land/p/demo/json" "gno.land/p/demo/ufmt" ) From d63918fe42e578bae037fa7a4987ed445804fa89 Mon Sep 17 00:00:00 2001 From: ltzmaxwell Date: Tue, 15 Oct 2024 20:59:39 +0800 Subject: [PATCH 06/64] fix(gnovm): correct type for shift expression (#1775) [shift operator where first operand is an untyped bigint always results in a bigint](https://github.com/gnolang/gno/issues/1462) is not resolved by #1426, it's fixed by this one. ================================================================= 1. This is a fix to gnolang/gno/issues/1462; 3. **NOTE**: This PR should be reviewed following the potential merger of #1426, from which it is both decoupled and dependent. #1426 serves as base branch of this one. 4. **NOTE**: Currently, this PR displays all code including that from #1426, because it is being compared to the master branch instead of differing against #1426 directly. --------- Co-authored-by: Morgan Co-authored-by: Marc Vertes --- gnovm/pkg/gnolang/eval_test.go | 4 +- gnovm/pkg/gnolang/nodes.go | 1 + gnovm/pkg/gnolang/op_binary.go | 2 + gnovm/pkg/gnolang/op_call.go | 5 + gnovm/pkg/gnolang/preprocess.go | 194 ++++++++++++++---- gnovm/pkg/gnolang/type_check.go | 121 ++++++++--- gnovm/pkg/gnolang/values.go | 106 ++++------ gnovm/pkg/gnolang/values_conversions.go | 1 + gnovm/tests/files/types/cmp_slice.gno | 14 ++ .../files/types/explicit_conversion_0.gno | 13 ++ .../files/types/explicit_conversion_1.gno | 13 ++ .../files/types/explicit_conversion_2.gno | 14 ++ .../files/types/explicit_conversion_4.gno | 9 + .../files/types/explicit_conversion_5.gno | 9 + gnovm/tests/files/types/shift_a11.gno | 2 +- gnovm/tests/files/types/shift_a2.gno | 1 - gnovm/tests/files/types/shift_a4.gno | 1 - gnovm/tests/files/types/shift_a5.gno | 6 +- gnovm/tests/files/types/shift_a7.gno | 2 +- gnovm/tests/files/types/shift_b0.gno | 14 ++ gnovm/tests/files/types/shift_b1.gno | 14 ++ gnovm/tests/files/types/shift_b10.gno | 14 ++ gnovm/tests/files/types/shift_b11.gno | 14 ++ gnovm/tests/files/types/shift_b2.gno | 14 ++ gnovm/tests/files/types/shift_b3.gno | 32 +++ gnovm/tests/files/types/shift_b4.gno | 32 +++ gnovm/tests/files/types/shift_b5.gno | 31 +++ gnovm/tests/files/types/shift_b6.gno | 30 +++ gnovm/tests/files/types/shift_b6a.gno | 31 +++ gnovm/tests/files/types/shift_b7.gno | 13 ++ gnovm/tests/files/types/shift_b8.gno | 14 ++ gnovm/tests/files/types/shift_b9.gno | 14 ++ gnovm/tests/files/types/shift_c10.gno | 12 ++ gnovm/tests/files/types/shift_c3.gno | 14 ++ gnovm/tests/files/types/shift_c4.gno | 14 ++ gnovm/tests/files/types/shift_c5.gno | 10 + gnovm/tests/files/types/shift_c6.gno | 14 ++ gnovm/tests/files/types/shift_c7.gno | 14 ++ gnovm/tests/files/types/shift_c8.gno | 14 ++ gnovm/tests/files/types/shift_c9.gno | 14 ++ gnovm/tests/files/types/shift_d11.gno | 21 ++ gnovm/tests/files/types/shift_d12.gno | 16 ++ gnovm/tests/files/types/shift_d13.gno | 17 ++ gnovm/tests/files/types/shift_d14.gno | 18 ++ gnovm/tests/files/types/shift_d15.gno | 10 + gnovm/tests/files/types/shift_d16.gno | 10 + gnovm/tests/files/types/shift_d21.gno | 10 + gnovm/tests/files/types/shift_d24.gno | 10 + gnovm/tests/files/types/shift_d25.gno | 10 + gnovm/tests/files/types/shift_d26.gno | 11 + gnovm/tests/files/types/shift_d27.gno | 11 + gnovm/tests/files/types/shift_d28.gno | 11 + gnovm/tests/files/types/shift_d29.gno | 14 ++ gnovm/tests/files/types/shift_d3.gno | 9 + gnovm/tests/files/types/shift_d30.gno | 14 ++ gnovm/tests/files/types/shift_d32.gno | 14 ++ gnovm/tests/files/types/shift_d32a.gno | 13 ++ gnovm/tests/files/types/shift_d33.gno | 14 ++ gnovm/tests/files/types/shift_d34.gno | 13 ++ gnovm/tests/files/types/shift_d35.gno | 14 ++ gnovm/tests/files/types/shift_d36.gno | 14 ++ gnovm/tests/files/types/shift_d37.gno | 9 + gnovm/tests/files/types/shift_d38.gno | 8 + gnovm/tests/files/types/shift_d39.gno | 16 ++ gnovm/tests/files/types/shift_d4.gno | 9 + gnovm/tests/files/types/shift_d40.gno | 10 + gnovm/tests/files/types/shift_d41.gno | 10 + gnovm/tests/files/types/shift_d42.gno | 14 ++ gnovm/tests/files/types/shift_d43.gno | 10 + gnovm/tests/files/types/shift_d44.gno | 10 + gnovm/tests/files/types/shift_d45.gno | 10 + gnovm/tests/files/types/shift_d46.gno | 10 + gnovm/tests/files/types/shift_d47.gno | 26 +++ gnovm/tests/files/types/shift_d48.gno | 23 +++ gnovm/tests/files/types/shift_d4a.gno | 9 + gnovm/tests/files/types/shift_d5.gno | 10 + gnovm/tests/files/types/shift_d50.gno | 13 ++ gnovm/tests/files/types/shift_d51.gno | 10 + gnovm/tests/files/types/shift_d52.gno | 10 + gnovm/tests/files/types/shift_d53.gno | 12 ++ gnovm/tests/files/types/shift_d54.gno | 14 ++ gnovm/tests/files/types/shift_d55.gno | 16 ++ gnovm/tests/files/types/shift_d56.gno | 16 ++ gnovm/tests/files/types/shift_d5a.gno | 10 + gnovm/tests/files/types/shift_d5b.gno | 10 + gnovm/tests/files/types/shift_d6.gno | 18 ++ gnovm/tests/files/types/shift_d9.gno | 9 + gnovm/tests/files/types/shift_e0.gno | 8 + gnovm/tests/files/types/shift_e1.gno | 8 + gnovm/tests/files/types/shift_e1a.gno | 8 + gnovm/tests/files/types/shift_e2.gno | 8 + gnovm/tests/files/types/shift_e3.gno | 9 + gnovm/tests/files/types/shift_e4.gno | 9 + gnovm/tests/files/types/shift_e5.gno | 9 + gnovm/tests/files/types/shift_e6.gno | 9 + gnovm/tests/files/types/shift_e7.gno | 9 + gnovm/tests/files/types/shift_e7a.gno | 9 + gnovm/tests/files/types/shift_e7b.gno | 8 + gnovm/tests/files/types/shift_e8.gno | 9 + gnovm/tests/files/types/shift_e9.gno | 11 + gnovm/tests/files/types/shift_e9a.gno | 11 + gnovm/tests/files/types/shift_f1a.gno | 12 ++ gnovm/tests/files/types/shift_f1b.gno | 12 ++ gnovm/tests/files/types/shift_f2.gno | 10 + gnovm/tests/files/types/shift_f2a.gno | 10 + gnovm/tests/files/types/shift_f2b.gno | 10 + gnovm/tests/files/types/shift_f2c.gno | 10 + gnovm/tests/files/types/shift_f2d.gno | 10 + gnovm/tests/files/types/shift_f2e.gno | 10 + gnovm/tests/files/types/shift_f3.gno | 10 + gnovm/tests/files/types/shift_f3a.gno | 10 + gnovm/tests/files/types/shift_f3b.gno | 10 + gnovm/tests/files/types/shift_f3c.gno | 10 + gnovm/tests/files/types/shift_f3d.gno | 10 + gnovm/tests/files/types/shift_f4.gno | 10 + gnovm/tests/files/types/shift_f5.gno | 10 + gnovm/tests/files/types/shift_g.gno | 18 ++ 117 files changed, 1640 insertions(+), 144 deletions(-) create mode 100644 gnovm/tests/files/types/cmp_slice.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_0.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_1.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_2.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_4.gno create mode 100644 gnovm/tests/files/types/explicit_conversion_5.gno create mode 100644 gnovm/tests/files/types/shift_b0.gno create mode 100644 gnovm/tests/files/types/shift_b1.gno create mode 100644 gnovm/tests/files/types/shift_b10.gno create mode 100644 gnovm/tests/files/types/shift_b11.gno create mode 100644 gnovm/tests/files/types/shift_b2.gno create mode 100644 gnovm/tests/files/types/shift_b3.gno create mode 100644 gnovm/tests/files/types/shift_b4.gno create mode 100644 gnovm/tests/files/types/shift_b5.gno create mode 100644 gnovm/tests/files/types/shift_b6.gno create mode 100644 gnovm/tests/files/types/shift_b6a.gno create mode 100644 gnovm/tests/files/types/shift_b7.gno create mode 100644 gnovm/tests/files/types/shift_b8.gno create mode 100644 gnovm/tests/files/types/shift_b9.gno create mode 100644 gnovm/tests/files/types/shift_c10.gno create mode 100644 gnovm/tests/files/types/shift_c3.gno create mode 100644 gnovm/tests/files/types/shift_c4.gno create mode 100644 gnovm/tests/files/types/shift_c5.gno create mode 100644 gnovm/tests/files/types/shift_c6.gno create mode 100644 gnovm/tests/files/types/shift_c7.gno create mode 100644 gnovm/tests/files/types/shift_c8.gno create mode 100644 gnovm/tests/files/types/shift_c9.gno create mode 100644 gnovm/tests/files/types/shift_d11.gno create mode 100644 gnovm/tests/files/types/shift_d12.gno create mode 100644 gnovm/tests/files/types/shift_d13.gno create mode 100644 gnovm/tests/files/types/shift_d14.gno create mode 100644 gnovm/tests/files/types/shift_d15.gno create mode 100644 gnovm/tests/files/types/shift_d16.gno create mode 100644 gnovm/tests/files/types/shift_d21.gno create mode 100644 gnovm/tests/files/types/shift_d24.gno create mode 100644 gnovm/tests/files/types/shift_d25.gno create mode 100644 gnovm/tests/files/types/shift_d26.gno create mode 100644 gnovm/tests/files/types/shift_d27.gno create mode 100644 gnovm/tests/files/types/shift_d28.gno create mode 100644 gnovm/tests/files/types/shift_d29.gno create mode 100644 gnovm/tests/files/types/shift_d3.gno create mode 100644 gnovm/tests/files/types/shift_d30.gno create mode 100644 gnovm/tests/files/types/shift_d32.gno create mode 100644 gnovm/tests/files/types/shift_d32a.gno create mode 100644 gnovm/tests/files/types/shift_d33.gno create mode 100644 gnovm/tests/files/types/shift_d34.gno create mode 100644 gnovm/tests/files/types/shift_d35.gno create mode 100644 gnovm/tests/files/types/shift_d36.gno create mode 100644 gnovm/tests/files/types/shift_d37.gno create mode 100644 gnovm/tests/files/types/shift_d38.gno create mode 100644 gnovm/tests/files/types/shift_d39.gno create mode 100644 gnovm/tests/files/types/shift_d4.gno create mode 100644 gnovm/tests/files/types/shift_d40.gno create mode 100644 gnovm/tests/files/types/shift_d41.gno create mode 100644 gnovm/tests/files/types/shift_d42.gno create mode 100644 gnovm/tests/files/types/shift_d43.gno create mode 100644 gnovm/tests/files/types/shift_d44.gno create mode 100644 gnovm/tests/files/types/shift_d45.gno create mode 100644 gnovm/tests/files/types/shift_d46.gno create mode 100644 gnovm/tests/files/types/shift_d47.gno create mode 100644 gnovm/tests/files/types/shift_d48.gno create mode 100644 gnovm/tests/files/types/shift_d4a.gno create mode 100644 gnovm/tests/files/types/shift_d5.gno create mode 100644 gnovm/tests/files/types/shift_d50.gno create mode 100644 gnovm/tests/files/types/shift_d51.gno create mode 100644 gnovm/tests/files/types/shift_d52.gno create mode 100644 gnovm/tests/files/types/shift_d53.gno create mode 100644 gnovm/tests/files/types/shift_d54.gno create mode 100644 gnovm/tests/files/types/shift_d55.gno create mode 100644 gnovm/tests/files/types/shift_d56.gno create mode 100644 gnovm/tests/files/types/shift_d5a.gno create mode 100644 gnovm/tests/files/types/shift_d5b.gno create mode 100644 gnovm/tests/files/types/shift_d6.gno create mode 100644 gnovm/tests/files/types/shift_d9.gno create mode 100644 gnovm/tests/files/types/shift_e0.gno create mode 100644 gnovm/tests/files/types/shift_e1.gno create mode 100644 gnovm/tests/files/types/shift_e1a.gno create mode 100644 gnovm/tests/files/types/shift_e2.gno create mode 100644 gnovm/tests/files/types/shift_e3.gno create mode 100644 gnovm/tests/files/types/shift_e4.gno create mode 100644 gnovm/tests/files/types/shift_e5.gno create mode 100644 gnovm/tests/files/types/shift_e6.gno create mode 100644 gnovm/tests/files/types/shift_e7.gno create mode 100644 gnovm/tests/files/types/shift_e7a.gno create mode 100644 gnovm/tests/files/types/shift_e7b.gno create mode 100644 gnovm/tests/files/types/shift_e8.gno create mode 100644 gnovm/tests/files/types/shift_e9.gno create mode 100644 gnovm/tests/files/types/shift_e9a.gno create mode 100644 gnovm/tests/files/types/shift_f1a.gno create mode 100644 gnovm/tests/files/types/shift_f1b.gno create mode 100644 gnovm/tests/files/types/shift_f2.gno create mode 100644 gnovm/tests/files/types/shift_f2a.gno create mode 100644 gnovm/tests/files/types/shift_f2b.gno create mode 100644 gnovm/tests/files/types/shift_f2c.gno create mode 100644 gnovm/tests/files/types/shift_f2d.gno create mode 100644 gnovm/tests/files/types/shift_f2e.gno create mode 100644 gnovm/tests/files/types/shift_f3.gno create mode 100644 gnovm/tests/files/types/shift_f3a.gno create mode 100644 gnovm/tests/files/types/shift_f3b.gno create mode 100644 gnovm/tests/files/types/shift_f3c.gno create mode 100644 gnovm/tests/files/types/shift_f3d.gno create mode 100644 gnovm/tests/files/types/shift_f4.gno create mode 100644 gnovm/tests/files/types/shift_f5.gno create mode 100644 gnovm/tests/files/types/shift_g.gno diff --git a/gnovm/pkg/gnolang/eval_test.go b/gnovm/pkg/gnolang/eval_test.go index 9acf4cc89f0..9b83d673767 100644 --- a/gnovm/pkg/gnolang/eval_test.go +++ b/gnovm/pkg/gnolang/eval_test.go @@ -40,8 +40,8 @@ func TestEvalFiles(t *testing.T) { 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) + if wantOut != "" && strings.TrimSpace(out) != strings.TrimSpace(wantOut) { + t.Fatalf("unexpected output\nWant: \"%s\"\n Got: \"%s\"", wantOut, out) } }) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index b18ed157ca6..8927eafcfb2 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -2119,6 +2119,7 @@ const ( ATTR_IOTA GnoAttribute = "ATTR_IOTA" ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED" ATTR_INJECTED GnoAttribute = "ATTR_INJECTED" + ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" ) var rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]+$`) diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index db3c1e5695c..24123d285ad 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -1097,6 +1097,7 @@ func xorAssign(lv, rv *TypedValue) { // for doOpShl and doOpShlAssign. func shlAssign(lv, rv *TypedValue) { + rv.AssertNonNegative("runtime error: negative shift amount") // set the result in lv. // NOTE: baseOf(rv.T) is always UintType. switch baseOf(lv.T) { @@ -1136,6 +1137,7 @@ func shlAssign(lv, rv *TypedValue) { // for doOpShr and doOpShrAssign. func shrAssign(lv, rv *TypedValue) { + rv.AssertNonNegative("runtime error: negative shift amount") // set the result in lv. // NOTE: baseOf(rv.T) is always UintType. switch baseOf(lv.T) { diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 15531ec610d..510c308a86a 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -27,6 +27,11 @@ func (m *Machine) doOpPrecall() { case TypeValue: // Do not pop type yet. // No need for frames. + xv := m.PeekValue(1) + if cx.GetAttribute(ATTR_SHIFT_RHS) == true { + xv.AssertNonNegative("runtime error: negative shift amount") + } + m.PushOp(OpConvert) if debug { if len(cx.Args) != 1 { diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 9168fc6f7c1..df1f7bab498 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1025,7 +1025,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { isShift := n.Op == SHL || n.Op == SHR if isShift { // check LHS type compatibility - n.checkShiftLhs(lt) + n.assertShiftExprCompatible1(store, last, lt, rt) // checkOrConvert RHS if baseOf(rt) != UintType { // convert n.Right to (gno) uint type, @@ -1036,6 +1036,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { Op: n.Op, Right: rn, } + n2.Right.SetAttribute(ATTR_SHIFT_RHS, true) resn := Preprocess(store, last, n2) return resn, TRANS_CONTINUE } @@ -1097,12 +1098,34 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: binary operations are always computed in // gno, never with reflect. } else { - // convert n.Left to right type. - checkOrConvertType(store, last, &n.Left, rt, false) + // right is untyped const, left is not const, typed/untyped + checkUntypedShiftExpr := func(x Expr) { + if bx, ok := x.(*BinaryExpr); ok { + slt := evalStaticTypeOf(store, last, bx.Left) + if bx.Op == SHL || bx.Op == SHR { + srt := evalStaticTypeOf(store, last, bx.Right) + bx.assertShiftExprCompatible1(store, last, slt, srt) + } + } + } + + if !isUntyped(rt) { // right is typed + checkOrConvertType(store, last, &n.Left, rt, false) + } else { + if shouldSwapOnSpecificity(lt, rt) { + checkUntypedShiftExpr(n.Right) + } else { + checkUntypedShiftExpr(n.Left) + } + } } } else if lcx.T == nil { // LHS is nil. // convert n.Left to typed-nil type. checkOrConvertType(store, last, &n.Left, rt, false) + } else { + if isUntyped(rt) { + checkOrConvertType(store, last, &n.Right, lt, false) + } } } else if ric { // right is const, left is not if isUntyped(rcx.T) { @@ -1134,12 +1157,33 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: binary operations are always computed in // gno, never with reflect. } else { - // convert n.Right to left type. - checkOrConvertType(store, last, &n.Right, lt, false) + // right is untyped const, left is not const, typed or untyped + checkUntypedShiftExpr := func(x Expr) { + if bx, ok := x.(*BinaryExpr); ok { + if bx.Op == SHL || bx.Op == SHR { + srt := evalStaticTypeOf(store, last, bx.Right) + bx.assertShiftExprCompatible1(store, last, rt, srt) + } + } + } + // both untyped, e.g. 1<>=. convertType(store, last, &n.Rhs[0], UintType) } else if n.Op == ADD_ASSIGN || n.Op == SUB_ASSIGN || n.Op == MUL_ASSIGN || n.Op == QUO_ASSIGN || n.Op == REM_ASSIGN { @@ -2281,10 +2343,15 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { vt := evalStaticTypeOf(store, last, vx) sts[i] = vt } - } else { + } else { // T is nil, n not const // convert n.Value to default type. for i, vx := range n.Values { - convertIfConst(store, last, vx) + if cx, ok := vx.(*ConstExpr); ok { + convertConst(store, last, cx, nil) + // convertIfConst(store, last, vx) + } else { + checkOrConvertType(store, last, &vx, nil, false) + } vt := evalStaticTypeOf(store, last, vx) sts[i] = vt } @@ -2840,9 +2907,25 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative assertAssignableTo(cx.T, t, autoNative) } } else if bx, ok := (*x).(*BinaryExpr); ok && (bx.Op == SHL || bx.Op == SHR) { - // "push" expected type into shift binary's left operand. recursively. - checkOrConvertType(store, last, &bx.Left, t, autoNative) - } else if *x != nil { // XXX if x != nil && t != nil { + xt := evalStaticTypeOf(store, last, *x) + if debug { + debug.Printf("shift, xt: %v, Op: %v, t: %v \n", xt, bx.Op, t) + } + if isUntyped(xt) { + // check assignable first, see: types/shift_b6.gno + assertAssignableTo(xt, t, autoNative) + + if t == nil || t.Kind() == InterfaceKind { + t = defaultTypeOf(xt) + } + + bx.assertShiftExprCompatible2(t) + checkOrConvertType(store, last, &bx.Left, t, autoNative) + } else { + assertAssignableTo(xt, t, autoNative) + } + return + } else if *x != nil { xt := evalStaticTypeOf(store, last, *x) if t != nil { assertAssignableTo(xt, t, autoNative) @@ -2853,19 +2936,53 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative switch bx.Op { case ADD, SUB, MUL, QUO, REM, BAND, BOR, XOR, BAND_NOT, LAND, LOR: - // push t into bx.Left and bx.Right - checkOrConvertType(store, last, &bx.Left, t, autoNative) - checkOrConvertType(store, last, &bx.Right, t, autoNative) - return - case SHL, SHR: - // push t into bx.Left - checkOrConvertType(store, last, &bx.Left, t, autoNative) + lt := evalStaticTypeOf(store, last, bx.Left) + rt := evalStaticTypeOf(store, last, bx.Right) + if t != nil { + // push t into bx.Left and bx.Right + checkOrConvertType(store, last, &bx.Left, t, autoNative) + checkOrConvertType(store, last, &bx.Right, t, autoNative) + return + } else { + if shouldSwapOnSpecificity(lt, rt) { + // e.g. 1.0< string)) to type uint diff --git a/gnovm/tests/files/types/shift_a2.gno b/gnovm/tests/files/types/shift_a2.gno index 91072929306..726d5415b15 100644 --- a/gnovm/tests/files/types/shift_a2.gno +++ b/gnovm/tests/files/types/shift_a2.gno @@ -1,6 +1,5 @@ package main -// both typed(different) const func main() { println(1 << int(1)) println(1 >> int(1)) diff --git a/gnovm/tests/files/types/shift_a4.gno b/gnovm/tests/files/types/shift_a4.gno index 3561929b672..694d771f190 100644 --- a/gnovm/tests/files/types/shift_a4.gno +++ b/gnovm/tests/files/types/shift_a4.gno @@ -1,6 +1,5 @@ package main -// both typed(different) const func main() { println(1 << 1.0) println(1 >> 1.0) diff --git a/gnovm/tests/files/types/shift_a5.gno b/gnovm/tests/files/types/shift_a5.gno index a0b7652c6d1..5d2c4304732 100644 --- a/gnovm/tests/files/types/shift_a5.gno +++ b/gnovm/tests/files/types/shift_a5.gno @@ -1,10 +1,10 @@ package main -// TODO: support this? func main() { println(1.0 << 1) println(1.0 >> 1) } -// Error: -// main/files/types/shift_a5.gno:5:10: operator << not defined on: BigdecKind +// Output: +// 2 +// 0 diff --git a/gnovm/tests/files/types/shift_a7.gno b/gnovm/tests/files/types/shift_a7.gno index 62151c5cfc5..cd1b3d95ec7 100644 --- a/gnovm/tests/files/types/shift_a7.gno +++ b/gnovm/tests/files/types/shift_a7.gno @@ -6,4 +6,4 @@ func main() { } // Error: -// main/files/types/shift_a7.gno:3:1: cannot convert StringKind to UintKind +// main/files/types/shift_a7.gno:5:10: cannot convert (const ("a" string)) to type uint diff --git a/gnovm/tests/files/types/shift_b0.gno b/gnovm/tests/files/types/shift_b0.gno new file mode 100644 index 00000000000..fa9ee4ed2a0 --- /dev/null +++ b/gnovm/tests/files/types/shift_b0.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 2 + r := uint64(1 << x) + println(r) + fmt.Printf("%T \n", r) +} + +// Output: +// 4 +// uint64 diff --git a/gnovm/tests/files/types/shift_b1.gno b/gnovm/tests/files/types/shift_b1.gno new file mode 100644 index 00000000000..403887269c0 --- /dev/null +++ b/gnovm/tests/files/types/shift_b1.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 2 + r := uint64(1< bigint does not implement main.R (missing method foo) diff --git a/gnovm/tests/files/types/shift_b6a.gno b/gnovm/tests/files/types/shift_b6a.gno new file mode 100644 index 00000000000..26b7f1b2ea1 --- /dev/null +++ b/gnovm/tests/files/types/shift_b6a.gno @@ -0,0 +1,31 @@ +package main + +import "fmt" + +type R interface { + foo() +} + +type U64 uint64 + +func (u64 U64) foo() { + println("bar") +} + +func bar(r R) { + r.foo() +} + +func main() { + x := 2 + var r R + r = U64(1) << x + + r.foo() + + fmt.Printf("%T \n", r) // TODO: should output main.U64 rather than the underlying type +} + +// Output: +// bar +// uint64 diff --git a/gnovm/tests/files/types/shift_b7.gno b/gnovm/tests/files/types/shift_b7.gno new file mode 100644 index 00000000000..ccc6cd41b7f --- /dev/null +++ b/gnovm/tests/files/types/shift_b7.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + x := 2 + r := float32(1<>2) +} + +// Output: +// 4 0 diff --git a/gnovm/tests/files/types/shift_c3.gno b/gnovm/tests/files/types/shift_c3.gno new file mode 100644 index 00000000000..6ca9a8b7cc2 --- /dev/null +++ b/gnovm/tests/files/types/shift_c3.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 1 + r := uint(+(1 << x)) + println(r) + fmt.Printf("%T \n", r) +} + +// Output: +// 2 +// uint diff --git a/gnovm/tests/files/types/shift_c4.gno b/gnovm/tests/files/types/shift_c4.gno new file mode 100644 index 00000000000..55b5fa782d7 --- /dev/null +++ b/gnovm/tests/files/types/shift_c4.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + x := 63 + r := int32(+(1<>x) +} + +// Output: +// uint64 +// int64 +// 2048 +// 0 diff --git a/gnovm/tests/files/types/shift_d12.gno b/gnovm/tests/files/types/shift_d12.gno new file mode 100644 index 00000000000..3d8c6e3de16 --- /dev/null +++ b/gnovm/tests/files/types/shift_d12.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func foo(a uint64, b float32) { + fmt.Printf("%T \n", a) + println(a) +} + +func main() { + x := 11 + foo(1<>x) +} + +// Error: +// main/files/types/shift_d12.gno:12:2: operator >> not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d13.gno b/gnovm/tests/files/types/shift_d13.gno new file mode 100644 index 00000000000..0ab495c1a26 --- /dev/null +++ b/gnovm/tests/files/types/shift_d13.gno @@ -0,0 +1,17 @@ +package main + +import "fmt" + +// it's like assign +func foo(a uint64, b float32) { + fmt.Printf("%T \n", a) + println(a) +} + +func main() { + x := 11 + foo(1<>x) +} + +// Error: +// main/files/types/shift_d13.gno:13:2: cannot use int as float32 diff --git a/gnovm/tests/files/types/shift_d14.gno b/gnovm/tests/files/types/shift_d14.gno new file mode 100644 index 00000000000..8458cf94ffb --- /dev/null +++ b/gnovm/tests/files/types/shift_d14.gno @@ -0,0 +1,18 @@ +package main + +import "fmt" + +// it's like assign +func foo(a uint64, b int64) { + fmt.Printf("%T\n", a) + println(a) +} + +func main() { + x := 11 + foo(1<>x) +} + +// Output: +// uint64 +// 2048 diff --git a/gnovm/tests/files/types/shift_d15.gno b/gnovm/tests/files/types/shift_d15.gno new file mode 100644 index 00000000000..a29108aef5a --- /dev/null +++ b/gnovm/tests/files/types/shift_d15.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 64 + y := uint64(1 << x) + println(y) +} + +// Output: +// 0 diff --git a/gnovm/tests/files/types/shift_d16.gno b/gnovm/tests/files/types/shift_d16.gno new file mode 100644 index 00000000000..3b7fb0aec50 --- /dev/null +++ b/gnovm/tests/files/types/shift_d16.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 64 + y := uint64(1<>2) //special case with == !=, untyped bool + println(r) +} + +// Error: +// main/files/types/shift_d4.gno:4:7: cannot convert BoolKind to Uint64Kind diff --git a/gnovm/tests/files/types/shift_d40.gno b/gnovm/tests/files/types/shift_d40.gno new file mode 100644 index 00000000000..8840f8b7322 --- /dev/null +++ b/gnovm/tests/files/types/shift_d40.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 2 + s := []float32{1 << a} + println(s[0]) +} + +// Error: +// main/files/types/shift_d40.gno:5:7: operator << not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d41.gno b/gnovm/tests/files/types/shift_d41.gno new file mode 100644 index 00000000000..bf46da524f7 --- /dev/null +++ b/gnovm/tests/files/types/shift_d41.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 2 + s := map[string]float32{"k": 1 << a} + println(s["k"]) +} + +// Error: +// main/files/types/shift_d41.gno:5:7: operator << not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d42.gno b/gnovm/tests/files/types/shift_d42.gno new file mode 100644 index 00000000000..c2bbfe94e2b --- /dev/null +++ b/gnovm/tests/files/types/shift_d42.gno @@ -0,0 +1,14 @@ +package main + +func main() { + type S struct { + a float32 + } + s := S{ + a: 1 << 2, + } + println(s.a) +} + +// Output: +// 4 diff --git a/gnovm/tests/files/types/shift_d43.gno b/gnovm/tests/files/types/shift_d43.gno new file mode 100644 index 00000000000..e9b0032ac9a --- /dev/null +++ b/gnovm/tests/files/types/shift_d43.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 2 + s := map[string]interface{}{"k": 1 << a} + println(s["k"]) +} + +// Output: +// 4 diff --git a/gnovm/tests/files/types/shift_d44.gno b/gnovm/tests/files/types/shift_d44.gno new file mode 100644 index 00000000000..0ef024f1e6b --- /dev/null +++ b/gnovm/tests/files/types/shift_d44.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + b := 1 + (a == b)++ // LHS is untyped bool, determined in preprocess +} + +// Error: +// main/files/types/shift_d44.gno:6:2: operator ++ not defined on: BoolKind diff --git a/gnovm/tests/files/types/shift_d45.gno b/gnovm/tests/files/types/shift_d45.gno new file mode 100644 index 00000000000..5c504d7d616 --- /dev/null +++ b/gnovm/tests/files/types/shift_d45.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := uint64(1 << x) + println(y) +} + +// Output: +// 2048 diff --git a/gnovm/tests/files/types/shift_d46.gno b/gnovm/tests/files/types/shift_d46.gno new file mode 100644 index 00000000000..8490c751c88 --- /dev/null +++ b/gnovm/tests/files/types/shift_d46.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := uint64(1.0 << x) + println(y) +} + +// Output: +// 2048 diff --git a/gnovm/tests/files/types/shift_d47.gno b/gnovm/tests/files/types/shift_d47.gno new file mode 100644 index 00000000000..d50c3944e90 --- /dev/null +++ b/gnovm/tests/files/types/shift_d47.gno @@ -0,0 +1,26 @@ +package main + +var specialBytes [16]byte + +func main() { + for i, b := range []byte(`\.+*?()|[]{}^$`) { + specialBytes[b%16] |= 1 << (b / 16) + println(i, (1 << (b / 16)), specialBytes[b%16]) + } +} + +// Output: +// 0 32 32 +// 1 4 4 +// 2 4 4 +// 3 4 4 +// 4 8 8 +// 5 4 4 +// 6 4 4 +// 7 128 160 +// 8 32 36 +// 9 32 32 +// 10 128 164 +// 11 128 160 +// 12 32 36 +// 13 4 4 diff --git a/gnovm/tests/files/types/shift_d48.gno b/gnovm/tests/files/types/shift_d48.gno new file mode 100644 index 00000000000..2ec6782c7f0 --- /dev/null +++ b/gnovm/tests/files/types/shift_d48.gno @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/gnolang/gno/_test/net/http" +) + +type extendedRequest struct { + Request http.Request + + Data string +} + +func main() { + r := extendedRequest{} + // req := &r.Request + + println(r) + // XXX removed temporarily until recursion detection implemented for sprintString(). + // println(req) +} + +// Output: +// (struct{(struct{( string),( string),(0 int),(0 int),(nil github.com/gnolang/gno/_test/net/http.Header),(undefined),(0 int64),(nil []string),(false bool),( string),(nil github.com/gnolang/gno/_test/net/http.Values),(nil github.com/gnolang/gno/_test/net/http.Values),(nil github.com/gnolang/gno/_test/net/http.Header),( string),( string),(nil *github.com/gnolang/gno/_test/net/http.Response)} github.com/gnolang/gno/_test/net/http.Request),( string)} main.extendedRequest) diff --git a/gnovm/tests/files/types/shift_d4a.gno b/gnovm/tests/files/types/shift_d4a.gno new file mode 100644 index 00000000000..803da33ea64 --- /dev/null +++ b/gnovm/tests/files/types/shift_d4a.gno @@ -0,0 +1,9 @@ +package main + +func main() { + r := string(1<<2 == 1>>2) //special case with == !=, untyped bool + println(r) +} + +// Error: +// main/files/types/shift_d4a.gno:4:7: cannot convert BoolKind to StringKind diff --git a/gnovm/tests/files/types/shift_d5.gno b/gnovm/tests/files/types/shift_d5.gno new file mode 100644 index 00000000000..43c0e117f5e --- /dev/null +++ b/gnovm/tests/files/types/shift_d5.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := 1.0 << x // no const + println(y) +} + +// Error: +// main/files/types/shift_d5.gno:5:2: operator << not defined on: Float64Kind diff --git a/gnovm/tests/files/types/shift_d50.gno b/gnovm/tests/files/types/shift_d50.gno new file mode 100644 index 00000000000..fec552e48d7 --- /dev/null +++ b/gnovm/tests/files/types/shift_d50.gno @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + x := 11 + y := uint64(-(1.0 << 2) << x) + println(y) + fmt.Printf("%T \n", y) +} + +// Error: +// main/files/types/shift_d50.gno:7:7: bigint underflows target kind diff --git a/gnovm/tests/files/types/shift_d51.gno b/gnovm/tests/files/types/shift_d51.gno new file mode 100644 index 00000000000..bd2b432479f --- /dev/null +++ b/gnovm/tests/files/types/shift_d51.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1.0 + a <<= 1 + println(a) +} + +// Error: +// main/files/types/shift_d51.gno:5:2: operator <<= not defined on: Float64Kind diff --git a/gnovm/tests/files/types/shift_d52.gno b/gnovm/tests/files/types/shift_d52.gno new file mode 100644 index 00000000000..f998381ef1c --- /dev/null +++ b/gnovm/tests/files/types/shift_d52.gno @@ -0,0 +1,10 @@ +package main + +func main() { + a := 1 + a <<= 1 + println(a) +} + +// Output: +// 2 diff --git a/gnovm/tests/files/types/shift_d53.gno b/gnovm/tests/files/types/shift_d53.gno new file mode 100644 index 00000000000..575dc1e146b --- /dev/null +++ b/gnovm/tests/files/types/shift_d53.gno @@ -0,0 +1,12 @@ +package main + +import "fmt" + +func main() { + a := 1 // a is inferred as int + b := a << 3 // b is also int + fmt.Printf("%T, %T, %d, %d \n", a, b, a, b) +} + +// Output: +// int, int, 1, 8 diff --git a/gnovm/tests/files/types/shift_d54.gno b/gnovm/tests/files/types/shift_d54.gno new file mode 100644 index 00000000000..13266f44379 --- /dev/null +++ b/gnovm/tests/files/types/shift_d54.gno @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + a := 5 // infer type int + var b int32 = 10 + c := b + a<<2 + + fmt.Printf("%T, %d \n", c, c) +} + +// Error: +// main/files/types/shift_d54.gno:8:7: invalid operation: mismatched types int32 and int diff --git a/gnovm/tests/files/types/shift_d55.gno b/gnovm/tests/files/types/shift_d55.gno new file mode 100644 index 00000000000..58628376421 --- /dev/null +++ b/gnovm/tests/files/types/shift_d55.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func shiftReturn() int64 { + return 1 << 4 // The shift result is cast to int64 +} + +func main() { + r := shiftReturn() + + fmt.Printf("%T, %d \n", r, r) +} + +// Output: +// int64, 16 diff --git a/gnovm/tests/files/types/shift_d56.gno b/gnovm/tests/files/types/shift_d56.gno new file mode 100644 index 00000000000..3f734bb993e --- /dev/null +++ b/gnovm/tests/files/types/shift_d56.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func shiftReturn() int64 { + return 1<<4 + int(1) // The shift result is cast to int64 +} + +func main() { + r := shiftReturn() + + fmt.Printf("%T, %d \n", r, r) +} + +// Error: +// main/files/types/shift_d56.gno:6:2: cannot use int as int64 diff --git a/gnovm/tests/files/types/shift_d5a.gno b/gnovm/tests/files/types/shift_d5a.gno new file mode 100644 index 00000000000..8490c751c88 --- /dev/null +++ b/gnovm/tests/files/types/shift_d5a.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := uint64(1.0 << x) + println(y) +} + +// Output: +// 2048 diff --git a/gnovm/tests/files/types/shift_d5b.gno b/gnovm/tests/files/types/shift_d5b.gno new file mode 100644 index 00000000000..8c04105a450 --- /dev/null +++ b/gnovm/tests/files/types/shift_d5b.gno @@ -0,0 +1,10 @@ +package main + +func main() { + x := 11 + y := float32(1.0 << x) + println(y) +} + +// Error: +// main/files/types/shift_d5b.gno:5:7: operator << not defined on: Float32Kind diff --git a/gnovm/tests/files/types/shift_d6.gno b/gnovm/tests/files/types/shift_d6.gno new file mode 100644 index 00000000000..e2ce1d02157 --- /dev/null +++ b/gnovm/tests/files/types/shift_d6.gno @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func main() { + x := 11 + y := 1 << x + println(y) + fmt.Printf("%T\n", y) + fmt.Printf("%T\n", 1) + fmt.Printf("%T\n", x) +} + +// Output: +// 2048 +// int +// int +// int diff --git a/gnovm/tests/files/types/shift_d9.gno b/gnovm/tests/files/types/shift_d9.gno new file mode 100644 index 00000000000..e766e5e218d --- /dev/null +++ b/gnovm/tests/files/types/shift_d9.gno @@ -0,0 +1,9 @@ +package main + +func main() { + r := bool(1<<2+1 == 1>>2) + println(r) +} + +// Output: +// false diff --git a/gnovm/tests/files/types/shift_e0.gno b/gnovm/tests/files/types/shift_e0.gno new file mode 100644 index 00000000000..d5b75063d3e --- /dev/null +++ b/gnovm/tests/files/types/shift_e0.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 << -1) +} + +// Error: +// main/files/types/shift_e0.gno:4:10: invalid operation: negative shift count: (const (-1 bigint)) diff --git a/gnovm/tests/files/types/shift_e1.gno b/gnovm/tests/files/types/shift_e1.gno new file mode 100644 index 00000000000..343dee1f933 --- /dev/null +++ b/gnovm/tests/files/types/shift_e1.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1.0 << float32(2.58485848)) +} + +// Error: +// main/files/types/shift_e1.gno:4:10: invalid operation: invalid shift count: (const (2.5848584 float32)) diff --git a/gnovm/tests/files/types/shift_e1a.gno b/gnovm/tests/files/types/shift_e1a.gno new file mode 100644 index 00000000000..bb6bedd2016 --- /dev/null +++ b/gnovm/tests/files/types/shift_e1a.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1.0 << 2.0) +} + +// Output: +// 4 diff --git a/gnovm/tests/files/types/shift_e2.gno b/gnovm/tests/files/types/shift_e2.gno new file mode 100644 index 00000000000..192d5c1b3e9 --- /dev/null +++ b/gnovm/tests/files/types/shift_e2.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 << 1.25) +} + +// Error: +// main/files/types/shift_e2.gno:4:10: invalid operation: invalid shift count: (const (1.25 bigdec)) diff --git a/gnovm/tests/files/types/shift_e3.gno b/gnovm/tests/files/types/shift_e3.gno new file mode 100644 index 00000000000..81c803897c7 --- /dev/null +++ b/gnovm/tests/files/types/shift_e3.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := 1.25 + println(1 << x) +} + +// Error: +// main/files/types/shift_e3.gno:5:10: invalid operation: invalid shift count: x diff --git a/gnovm/tests/files/types/shift_e4.gno b/gnovm/tests/files/types/shift_e4.gno new file mode 100644 index 00000000000..02746eb04fe --- /dev/null +++ b/gnovm/tests/files/types/shift_e4.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := 1.25 + println(1 << x) +} + +// Error: +// main/files/types/shift_e4.gno:5:10: invalid operation: invalid shift count: x \ No newline at end of file diff --git a/gnovm/tests/files/types/shift_e5.gno b/gnovm/tests/files/types/shift_e5.gno new file mode 100644 index 00000000000..acd351bd50d --- /dev/null +++ b/gnovm/tests/files/types/shift_e5.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := -1 + println(1 << x) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_e6.gno b/gnovm/tests/files/types/shift_e6.gno new file mode 100644 index 00000000000..43cb2464132 --- /dev/null +++ b/gnovm/tests/files/types/shift_e6.gno @@ -0,0 +1,9 @@ +package main + +func main() { + x := -1 + println(1 >> x) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_e7.gno b/gnovm/tests/files/types/shift_e7.gno new file mode 100644 index 00000000000..c7d8aded350 --- /dev/null +++ b/gnovm/tests/files/types/shift_e7.gno @@ -0,0 +1,9 @@ +package main + +func main() { + y := 1 + y <<= -1 +} + +// Error: +// main/files/types/shift_e7.gno:5:2: invalid operation: negative shift count: (-1 bigint) diff --git a/gnovm/tests/files/types/shift_e7a.gno b/gnovm/tests/files/types/shift_e7a.gno new file mode 100644 index 00000000000..2e81fc102bc --- /dev/null +++ b/gnovm/tests/files/types/shift_e7a.gno @@ -0,0 +1,9 @@ +package main + +func main() { + a := float64(-100) + println(1 << a) +} + +// Error: +// main/files/types/shift_e7a.gno:5:10: invalid operation: invalid shift count: a diff --git a/gnovm/tests/files/types/shift_e7b.gno b/gnovm/tests/files/types/shift_e7b.gno new file mode 100644 index 00000000000..80766d2928e --- /dev/null +++ b/gnovm/tests/files/types/shift_e7b.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(1 << float64(-1)) +} + +// Error: +// main/files/types/shift_e7b.gno:4:10: invalid operation: invalid shift count: (const (-1 float64)) diff --git a/gnovm/tests/files/types/shift_e8.gno b/gnovm/tests/files/types/shift_e8.gno new file mode 100644 index 00000000000..1940dd9b8fb --- /dev/null +++ b/gnovm/tests/files/types/shift_e8.gno @@ -0,0 +1,9 @@ +package main + +func main() { + y := 1 + y <<= 1.25 +} + +// Error: +// main/files/types/shift_e8.gno:5:2: invalid operation: invalid shift count: (const (1.25 bigdec)) diff --git a/gnovm/tests/files/types/shift_e9.gno b/gnovm/tests/files/types/shift_e9.gno new file mode 100644 index 00000000000..2bd408860f2 --- /dev/null +++ b/gnovm/tests/files/types/shift_e9.gno @@ -0,0 +1,11 @@ +package main + +func main() { + x := -1 + y := 1 + y <<= x + println(y) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_e9a.gno b/gnovm/tests/files/types/shift_e9a.gno new file mode 100644 index 00000000000..03ce9343948 --- /dev/null +++ b/gnovm/tests/files/types/shift_e9a.gno @@ -0,0 +1,11 @@ +package main + +func main() { + x := -1 + y := 1 + y >>= x + println(y) +} + +// Error: +// runtime error: negative shift amount: (-1 int) diff --git a/gnovm/tests/files/types/shift_f1a.gno b/gnovm/tests/files/types/shift_f1a.gno new file mode 100644 index 00000000000..ca35144bacc --- /dev/null +++ b/gnovm/tests/files/types/shift_f1a.gno @@ -0,0 +1,12 @@ +package main + +func main() { + var s uint = 33 + + var u1 bool + u1 = 1< bigint NEQ bigdec diff --git a/gnovm/tests/files/types/shift_f2e.gno b/gnovm/tests/files/types/shift_f2e.gno new file mode 100644 index 00000000000..dec0a2a6626 --- /dev/null +++ b/gnovm/tests/files/types/shift_f2e.gno @@ -0,0 +1,10 @@ +package main + +func main() { + var s uint = 33 + var u2 = 1.0< Date: Tue, 15 Oct 2024 16:26:16 +0200 Subject: [PATCH 07/64] =?UTF-8?q?chore:=20farewell=20Dylan=20=F0=9F=91=8B?= =?UTF-8?q?=20(#2951)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3870ff30539..8566e861db9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -64,9 +64,9 @@ # GnoVM/Gnolang. /gnovm/ @jaekwon @moul @piux2 @thehowl /gnovm/stdlibs/ @thehowl -/gnovm/tests/ @jaekwon @deelawn @thehowl @mvertes +/gnovm/tests/ @jaekwon @thehowl @mvertes /gnovm/cmd/gno/ @moul @thehowl -/gnovm/pkg/gnolang/ @jaekwon @moul @piux2 @deelawn +/gnovm/pkg/gnolang/ @jaekwon @moul @piux2 /gnovm/pkg/doc/ @thehowl /gnovm/pkg/repl/ @mvertes @ajnavarro /gnovm/pkg/gnomod/ @thehowl From d741140c099f427e568ecd5f8ca82b983c94ac82 Mon Sep 17 00:00:00 2001 From: Malek Lahbib <111009238+MalekLahbib@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:25:45 +0200 Subject: [PATCH 08/64] fix(p/demo/uassert): amend ineffective assignment (#2936)
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- examples/gno.land/p/demo/uassert/uassert.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/p/demo/uassert/uassert.gno b/examples/gno.land/p/demo/uassert/uassert.gno index 2776e93dca9..f9c0ab3efc8 100644 --- a/examples/gno.land/p/demo/uassert/uassert.gno +++ b/examples/gno.land/p/demo/uassert/uassert.gno @@ -266,7 +266,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgs ...string) bool { if av, ok := actual.(string); ok { notEqual = ev != av ok_ = true - es, as = ev, as + es, as = ev, av } case std.Address: if av, ok := actual.(std.Address); ok { From 679301ab829ee576246b03c8381bab2212baa82d Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:52:43 +0200 Subject: [PATCH 09/64] fix(r/leon/config): fix config bug (#2934) ## Description Fixes a bug in `r/leon/config`.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [x] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- examples/gno.land/r/leon/config/config.gno | 20 +++++++++----------- examples/gno.land/r/leon/home/home.gno | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/examples/gno.land/r/leon/config/config.gno b/examples/gno.land/r/leon/config/config.gno index cbc1e537e3f..bc800ec8263 100644 --- a/examples/gno.land/r/leon/config/config.gno +++ b/examples/gno.land/r/leon/config/config.gno @@ -8,6 +8,9 @@ import ( var ( main std.Address // leon's main address backup std.Address // backup address + + ErrInvalidAddr = errors.New("leon's config: invalid address") + ErrUnauthorized = errors.New("leon's config: unauthorized") ) func init() { @@ -24,7 +27,7 @@ func Backup() std.Address { func SetAddress(a std.Address) error { if !a.IsValid() { - return errors.New("config: invalid address") + return ErrInvalidAddr } if err := checkAuthorized(); err != nil { @@ -37,7 +40,7 @@ func SetAddress(a std.Address) error { func SetBackup(a std.Address) error { if !a.IsValid() { - return errors.New("config: invalid address") + return ErrInvalidAddr } if err := checkAuthorized(); err != nil { @@ -50,16 +53,11 @@ func SetBackup(a std.Address) error { func checkAuthorized() error { caller := std.PrevRealm().Addr() - if caller != main || caller != backup { - return errors.New("config: unauthorized") + isAuthorized := caller == main || caller == backup + + if !isAuthorized { + return ErrUnauthorized } return nil } - -func AssertAuthorized() { - caller := std.PrevRealm().Addr() - if caller != main || caller != backup { - panic("config: unauthorized") - } -} diff --git a/examples/gno.land/r/leon/home/home.gno b/examples/gno.land/r/leon/home/home.gno index 1f6a07e8959..ba688792a4c 100644 --- a/examples/gno.land/r/leon/home/home.gno +++ b/examples/gno.land/r/leon/home/home.gno @@ -34,13 +34,19 @@ TODO import r/gh } func UpdatePFP(url, caption string) { - config.AssertAuthorized() + if !isAuthorized(std.PrevRealm().Addr()) { + panic(config.ErrUnauthorized) + } + pfp = url pfpCaption = caption } func UpdateAboutMe(col1, col2 string) { - config.AssertAuthorized() + if !isAuthorized(std.PrevRealm().Addr()) { + panic(config.ErrUnauthorized) + } + abtMe[0] = col1 abtMe[1] = col2 } @@ -119,3 +125,7 @@ func renderMillipede() string { return out } + +func isAuthorized(addr std.Address) bool { + return addr == config.Address() || addr == config.Backup() +} From a73cb22e58d8b81413c35aa0b5b4dfece2dfecd3 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Tue, 15 Oct 2024 22:54:09 +0200 Subject: [PATCH 10/64] chore: fix issues reported by `go vet` (#2952) Passing `go vet` is the minimum level of code quality for a go project. This is addressed here for the full mono-repo. Mainly trivial changes, except for a few `copy lock` issues which could be more meaningful (kept for a separate pull request). Addresses #2954 (but not sufficient to close it yet). Hint for reviewers: it's easier to review each commit individually.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- gno.land/pkg/gnoweb/gnoweb.go | 4 ++-- gno.land/pkg/sdk/vm/builtins.go | 4 ++-- gno.land/pkg/sdk/vm/keeper_test.go | 18 +++++++-------- gnovm/pkg/gnomod/read.go | 2 +- gnovm/tests/file.go | 4 ++-- misc/logos/cmd/logos.go | 2 +- tm2/pkg/amino/wellknown.go | 1 - tm2/pkg/bft/abci/example/kvstore/helpers.go | 2 +- .../example/kvstore/persistent_kvstore.go | 2 +- tm2/pkg/bft/consensus/state.go | 22 +++++++++---------- tm2/pkg/bft/consensus/wal_generator.go | 2 +- tm2/pkg/bft/types/params.go | 6 ++--- tm2/pkg/crypto/hd/hdpath_test.go | 4 ++-- tm2/pkg/db/boltdb/boltdb.go | 4 ++-- tm2/pkg/db/memdb/mem_db.go | 2 +- tm2/pkg/p2p/switch.go | 2 +- tm2/pkg/sdk/bank/keeper_test.go | 2 +- tm2/pkg/sdk/baseapp.go | 4 ---- tm2/pkg/sdk/baseapp_test.go | 14 ++++++------ tm2/pkg/store/cache/store_test.go | 8 +++---- tm2/pkg/store/gas/store_test.go | 8 +++---- tm2/pkg/store/iavl/store_test.go | 4 ++-- tm2/pkg/store/prefix/store_test.go | 12 +++++----- 23 files changed, 64 insertions(+), 69 deletions(-) diff --git a/gno.land/pkg/gnoweb/gnoweb.go b/gno.land/pkg/gnoweb/gnoweb.go index 5377ae6a420..3e6249cf126 100644 --- a/gno.land/pkg/gnoweb/gnoweb.go +++ b/gno.land/pkg/gnoweb/gnoweb.go @@ -476,7 +476,7 @@ func handleNotFound(logger *slog.Logger, app gotuna.App, cfg *Config, path strin // decode path for non-ascii characters decodedPath, err := url.PathUnescape(path) if err != nil { - logger.Error("failed to decode path", err) + logger.Error("failed to decode path", "error", err) decodedPath = path } w.WriteHeader(http.StatusNotFound) @@ -491,7 +491,7 @@ func writeError(logger *slog.Logger, w http.ResponseWriter, err error) { if details := errors.Unwrap(err); details != nil { logger.Error("handler", "error", err, "details", details) } else { - logger.Error("handler", "error:", err) + logger.Error("handler", "error", err) } // XXX: writeError should return an error page template. diff --git a/gno.land/pkg/sdk/vm/builtins.go b/gno.land/pkg/sdk/vm/builtins.go index de58cd3e8ae..d4d6b6032b2 100644 --- a/gno.land/pkg/sdk/vm/builtins.go +++ b/gno.land/pkg/sdk/vm/builtins.go @@ -42,7 +42,7 @@ func (bnk *SDKBanker) TotalCoin(denom string) int64 { func (bnk *SDKBanker) IssueCoin(b32addr crypto.Bech32Address, denom string, amount int64) { addr := crypto.MustAddressFromString(string(b32addr)) - _, err := bnk.vmk.bank.AddCoins(bnk.ctx, addr, std.Coins{std.Coin{denom, amount}}) + _, err := bnk.vmk.bank.AddCoins(bnk.ctx, addr, std.Coins{std.Coin{Denom: denom, Amount: amount}}) if err != nil { panic(err) } @@ -50,7 +50,7 @@ func (bnk *SDKBanker) IssueCoin(b32addr crypto.Bech32Address, denom string, amou func (bnk *SDKBanker) RemoveCoin(b32addr crypto.Bech32Address, denom string, amount int64) { addr := crypto.MustAddressFromString(string(b32addr)) - _, err := bnk.vmk.bank.SubtractCoins(bnk.ctx, addr, std.Coins{std.Coin{denom, amount}}) + _, err := bnk.vmk.bank.SubtractCoins(bnk.ctx, addr, std.Coins{std.Coin{Denom: denom, Amount: amount}}) if err != nil { panic(err) } diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index 9257da2ddaf..f6c6b87419d 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -81,7 +81,7 @@ func TestVMKeeperOrigSend1(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -126,7 +126,7 @@ func TestVMKeeperOrigSend2(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -180,7 +180,7 @@ func TestVMKeeperOrigSend3(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -224,7 +224,7 @@ func TestVMKeeperRealmSend1(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -268,7 +268,7 @@ func TestVMKeeperRealmSend2(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -312,7 +312,7 @@ func TestVMKeeperOrigCallerInit(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test import "std" @@ -363,7 +363,7 @@ func TestVMKeeperRunSimple(t *testing.T) { env.acck.SetAccount(ctx, acc) files := []*std.MemFile{ - {"script.gno", ` + {Name: "script.gno", Body: ` package main func main() { @@ -402,7 +402,7 @@ func testVMKeeperRunImportStdlibs(t *testing.T, env testEnv) { env.acck.SetAccount(ctx, acc) files := []*std.MemFile{ - {"script.gno", ` + {Name: "script.gno", Body: ` package main import "std" @@ -474,7 +474,7 @@ func TestVMKeeperReinitialize(t *testing.T) { // Create test package. files := []*std.MemFile{ - {"init.gno", ` + {Name: "init.gno", Body: ` package test func Echo(msg string) string { diff --git a/gnovm/pkg/gnomod/read.go b/gnovm/pkg/gnomod/read.go index a7a600f8826..d6d771429d3 100644 --- a/gnovm/pkg/gnomod/read.go +++ b/gnovm/pkg/gnomod/read.go @@ -249,7 +249,7 @@ func (in *input) readToken() { // Otherwise, save comment for later attachment to syntax tree. in.endToken(_EOLCOMMENT) - in.comments = append(in.comments, modfile.Comment{in.token.pos, in.token.text, suffix}) + in.comments = append(in.comments, modfile.Comment{Start: in.token.pos, Token: in.token.text, Suffix: suffix}) return } diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index f6bd789f1bf..1be2a0516f9 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -597,12 +597,12 @@ func (tb *testBanker) TotalCoin(denom string) int64 { func (tb *testBanker) IssueCoin(addr crypto.Bech32Address, denom string, amt int64) { coins, _ := tb.coinTable[addr] - sum := coins.Add(std.Coins{{denom, amt}}) + sum := coins.Add(std.Coins{{Denom: denom, Amount: amt}}) tb.coinTable[addr] = sum } func (tb *testBanker) RemoveCoin(addr crypto.Bech32Address, denom string, amt int64) { coins, _ := tb.coinTable[addr] - rest := coins.Sub(std.Coins{{denom, amt}}) + rest := coins.Sub(std.Coins{{Denom: denom, Amount: amt}}) tb.coinTable[addr] = rest } diff --git a/misc/logos/cmd/logos.go b/misc/logos/cmd/logos.go index 3a374fecba2..ddb979111fb 100644 --- a/misc/logos/cmd/logos.go +++ b/misc/logos/cmd/logos.go @@ -162,7 +162,7 @@ func makeTestPage() *logos.BufferedElemView { // make a buffered page. ts := makeTestString() style := logos.DefaultStyle() - style.Padding = logos.Padding{2, 2, 2, 2} + style.Padding = logos.Padding{Left: 2, Top: 2, Right: 2, Bottom: 2} style.Border = logos.DefaultBorder() // TODO width shouldn't matter. page := logos.NewPage(ts, 84, true, style) diff --git a/tm2/pkg/amino/wellknown.go b/tm2/pkg/amino/wellknown.go index 8c8ff79695d..9dbafcbecec 100644 --- a/tm2/pkg/amino/wellknown.go +++ b/tm2/pkg/amino/wellknown.go @@ -210,7 +210,6 @@ func isJSONWellKnownType(rt reflect.Type) (wellKnown bool) { default: return false } - return false } // Returns ok=false if nothing was done because the default behavior is fine (or if err). diff --git a/tm2/pkg/bft/abci/example/kvstore/helpers.go b/tm2/pkg/bft/abci/example/kvstore/helpers.go index b72b4da4778..c2a89fa20b3 100644 --- a/tm2/pkg/bft/abci/example/kvstore/helpers.go +++ b/tm2/pkg/bft/abci/example/kvstore/helpers.go @@ -11,7 +11,7 @@ import ( func RandVal(i int) abci.ValidatorUpdate { pubkey := ed25519.GenPrivKey().PubKey() power := random.RandUint16() + 1 - v := abci.ValidatorUpdate{pubkey.Address(), pubkey, int64(power)} + v := abci.ValidatorUpdate{Address: pubkey.Address(), PubKey: pubkey, Power: int64(power)} return v } diff --git a/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go b/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go index 01a8a3a8b8c..b6d096667ac 100644 --- a/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go +++ b/tm2/pkg/bft/abci/example/kvstore/persistent_kvstore.go @@ -211,7 +211,7 @@ func (app *PersistentKVStoreApplication) execValidatorTx(tx []byte) (res abci.Re } // update - return app.updateValidator(abci.ValidatorUpdate{pubkey.Address(), pubkey, power}) + return app.updateValidator(abci.ValidatorUpdate{Address: pubkey.Address(), PubKey: pubkey, Power: power}) } // add, update, or remove a validator diff --git a/tm2/pkg/bft/consensus/state.go b/tm2/pkg/bft/consensus/state.go index 3f71dac368c..6faa40be20b 100644 --- a/tm2/pkg/bft/consensus/state.go +++ b/tm2/pkg/bft/consensus/state.go @@ -73,7 +73,7 @@ func (ti *timeoutInfo) GetHRS() cstypes.HRS { if ti == nil { return cstypes.HRS{} } else { - return cstypes.HRS{ti.Height, ti.Round, ti.Step} + return cstypes.HRS{Height: ti.Height, Round: ti.Round, Step: ti.Step} } } @@ -746,13 +746,13 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) { case cstypes.RoundStepNewRound: cs.enterPropose(ti.Height, 0) case cstypes.RoundStepPropose: - cs.evsw.FireEvent(cstypes.EventTimeoutPropose{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventTimeoutPropose{HRS: cs.RoundState.GetHRS()}) cs.enterPrevote(ti.Height, ti.Round) case cstypes.RoundStepPrevoteWait: - cs.evsw.FireEvent(cstypes.EventTimeoutWait{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventTimeoutWait{HRS: cs.RoundState.GetHRS()}) cs.enterPrecommit(ti.Height, ti.Round) case cstypes.RoundStepPrecommitWait: - cs.evsw.FireEvent(cstypes.EventTimeoutWait{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventTimeoutWait{HRS: cs.RoundState.GetHRS()}) cs.enterPrecommit(ti.Height, ti.Round) cs.enterNewRound(ti.Height, ti.Round+1) default: @@ -1126,7 +1126,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { } // At this point +2/3 prevoted for a particular block or nil. - cs.evsw.FireEvent(cstypes.EventPolka{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventPolka{HRS: cs.RoundState.GetHRS()}) // the latest POLRound should be this round. polRound, _ := cs.Votes.POLInfo() @@ -1143,7 +1143,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { cs.LockedRound = -1 cs.LockedBlock = nil cs.LockedBlockParts = nil - cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventUnlock{HRS: cs.RoundState.GetHRS()}) } cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{}) return @@ -1155,7 +1155,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { if cs.LockedBlock.HashesTo(blockID.Hash) { logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking") cs.LockedRound = round - cs.evsw.FireEvent(cstypes.EventRelock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventRelock{HRS: cs.RoundState.GetHRS()}) cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader) return } @@ -1170,7 +1170,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { cs.LockedRound = round cs.LockedBlock = cs.ProposalBlock cs.LockedBlockParts = cs.ProposalBlockParts - cs.evsw.FireEvent(cstypes.EventLock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventLock{HRS: cs.RoundState.GetHRS()}) cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader) return } @@ -1186,7 +1186,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) { cs.ProposalBlock = nil cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader) } - cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventUnlock{HRS: cs.RoundState.GetHRS()}) cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{}) } @@ -1591,7 +1591,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, return } - cs.evsw.FireEvent(types.EventVote{vote}) + cs.evsw.FireEvent(types.EventVote{Vote: vote}) switch vote.Type { case types.PrevoteType: @@ -1620,7 +1620,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, cs.LockedRound = -1 cs.LockedBlock = nil cs.LockedBlockParts = nil - cs.evsw.FireEvent(cstypes.EventUnlock{cs.RoundState.GetHRS()}) + cs.evsw.FireEvent(cstypes.EventUnlock{HRS: cs.RoundState.GetHRS()}) } // Update Valid* if we can. diff --git a/tm2/pkg/bft/consensus/wal_generator.go b/tm2/pkg/bft/consensus/wal_generator.go index fddcb4231e5..79c6e63c6a1 100644 --- a/tm2/pkg/bft/consensus/wal_generator.go +++ b/tm2/pkg/bft/consensus/wal_generator.go @@ -77,7 +77,7 @@ func (w *heightStopWAL) Write(m walm.WALMessage) error { } w.logger.Debug("WAL Write Message", "msg", m) - err := w.enc.Write(walm.TimedWALMessage{fixedTime, m}) + err := w.enc.Write(walm.TimedWALMessage{Time: fixedTime, Msg: m}) if err != nil { panic(fmt.Sprintf("failed to encode the msg %v", m)) } diff --git a/tm2/pkg/bft/types/params.go b/tm2/pkg/bft/types/params.go index 0b48da9329e..c2e8f304698 100644 --- a/tm2/pkg/bft/types/params.go +++ b/tm2/pkg/bft/types/params.go @@ -36,8 +36,8 @@ var validatorPubKeyTypeURLs = map[string]struct{}{ func DefaultConsensusParams() abci.ConsensusParams { return abci.ConsensusParams{ - DefaultBlockParams(), - DefaultValidatorParams(), + Block: DefaultBlockParams(), + Validator: DefaultValidatorParams(), } } @@ -51,7 +51,7 @@ func DefaultBlockParams() *abci.BlockParams { } func DefaultValidatorParams() *abci.ValidatorParams { - return &abci.ValidatorParams{[]string{ + return &abci.ValidatorParams{PubKeyTypeURLs: []string{ amino.GetTypeURL(ed25519.PubKeyEd25519{}), }} } diff --git a/tm2/pkg/crypto/hd/hdpath_test.go b/tm2/pkg/crypto/hd/hdpath_test.go index 31e806b2b1a..f79ee1151f7 100644 --- a/tm2/pkg/crypto/hd/hdpath_test.go +++ b/tm2/pkg/crypto/hd/hdpath_test.go @@ -17,7 +17,7 @@ func mnemonicToSeed(mnemonic string) []byte { return bip39.NewSeed(mnemonic, defaultBIP39Passphrase) } -func ExampleStringifyPathParams() { +func ExampleNewParams() { path := NewParams(44, 0, 0, false, 0) fmt.Println(path.String()) path = NewParams(44, 33, 7, true, 9) @@ -109,7 +109,7 @@ func TestParamsFromPath(t *testing.T) { } } -func ExampleSomeBIP32TestVecs() { +func ExampleDerivePrivateKeyForPath() { seed := mnemonicToSeed("barrel original fuel morning among eternal " + "filter ball stove pluck matrix mechanic") master, ch := ComputeMastersFromSeed(seed) diff --git a/tm2/pkg/db/boltdb/boltdb.go b/tm2/pkg/db/boltdb/boltdb.go index c35e3bb00e1..12aa20b8ce2 100644 --- a/tm2/pkg/db/boltdb/boltdb.go +++ b/tm2/pkg/db/boltdb/boltdb.go @@ -170,13 +170,13 @@ func (bdb *BoltDB) NewBatch() db.Batch { // It is safe to modify the contents of the argument after Set returns but not // before. func (bdb *boltDBBatch) Set(key, value []byte) { - bdb.ops = append(bdb.ops, internal.Operation{internal.OpTypeSet, key, value}) + bdb.ops = append(bdb.ops, internal.Operation{OpType: internal.OpTypeSet, Key: key, Value: value}) } // It is safe to modify the contents of the argument after Delete returns but // not before. func (bdb *boltDBBatch) Delete(key []byte) { - bdb.ops = append(bdb.ops, internal.Operation{internal.OpTypeDelete, key, nil}) + bdb.ops = append(bdb.ops, internal.Operation{OpType: internal.OpTypeDelete, Key: key}) } // NOTE: the operation is synchronous (see BoltDB for reasons) diff --git a/tm2/pkg/db/memdb/mem_db.go b/tm2/pkg/db/memdb/mem_db.go index 09b90b6be44..d39a9838cef 100644 --- a/tm2/pkg/db/memdb/mem_db.go +++ b/tm2/pkg/db/memdb/mem_db.go @@ -150,7 +150,7 @@ func (db *MemDB) NewBatch() dbm.Batch { db.mtx.Lock() defer db.mtx.Unlock() - return &internal.MemBatch{db, nil} + return &internal.MemBatch{DB: db} } // ---------------------------------------- diff --git a/tm2/pkg/p2p/switch.go b/tm2/pkg/p2p/switch.go index cecfc21f3ef..b2de68e1ae3 100644 --- a/tm2/pkg/p2p/switch.go +++ b/tm2/pkg/p2p/switch.go @@ -219,7 +219,7 @@ func (sw *Switch) OnStop() { if t, ok := sw.transport.(TransportLifecycle); ok { err := t.Close() if err != nil { - sw.Logger.Error("Error stopping transport on stop: ", err) + sw.Logger.Error("Error stopping transport on stop: ", "error", err) } } diff --git a/tm2/pkg/sdk/bank/keeper_test.go b/tm2/pkg/sdk/bank/keeper_test.go index 59b4c12689c..df2039a682c 100644 --- a/tm2/pkg/sdk/bank/keeper_test.go +++ b/tm2/pkg/sdk/bank/keeper_test.go @@ -133,7 +133,7 @@ func TestBankKeeper(t *testing.T) { // validate coins with invalid denoms or negative values cannot be sent // NOTE: We must use the Coin literal as the constructor does not allow // negative values. - err = bank.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{"FOOCOIN", -5}}) + err = bank.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: -5}}) require.Error(t, err) } diff --git a/tm2/pkg/sdk/baseapp.go b/tm2/pkg/sdk/baseapp.go index 671f18cf058..3cabc9df336 100644 --- a/tm2/pkg/sdk/baseapp.go +++ b/tm2/pkg/sdk/baseapp.go @@ -392,10 +392,6 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { default: return handleQueryCustom(app, path, req) } - - msg := "unknown query path " + req.Path - res.Error = ABCIError(std.ErrUnknownRequest(msg)) - return } func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { diff --git a/tm2/pkg/sdk/baseapp_test.go b/tm2/pkg/sdk/baseapp_test.go index c8884533b30..08e8191170a 100644 --- a/tm2/pkg/sdk/baseapp_test.go +++ b/tm2/pkg/sdk/baseapp_test.go @@ -47,7 +47,7 @@ func newTxCounter(txInt int64, msgInts ...int64) std.Tx { msgs := make([]std.Msg, len(msgInts)) for i, msgInt := range msgInts { - msgs[i] = msgCounter{msgInt, false} + msgs[i] = msgCounter{Counter: msgInt, FailOnHandler: false} } tx := std.Tx{Msgs: msgs} @@ -120,13 +120,13 @@ func TestLoadVersion(t *testing.T) { header := &bft.Header{ChainID: "test-chain", Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := store.CommitID{1, res.Data} + commitID1 := store.CommitID{Version: 1, Hash: res.Data} // execute a block, collect commit ID header = &bft.Header{ChainID: "test-chain", Height: 2} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res = app.Commit() - commitID2 := store.CommitID{2, res.Data} + commitID2 := store.CommitID{Version: 2, Hash: res.Data} // reload with LoadLatestVersion app = newBaseApp(name, db, pruningOpt) @@ -184,7 +184,7 @@ func TestLoadVersionInvalid(t *testing.T) { header := &bft.Header{ChainID: "test-chain", Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := store.CommitID{1, res.Data} + commitID1 := store.CommitID{Version: 1, Hash: res.Data} // create a new app with the stores mounted under the same cap key app = newBaseApp(name, db, pruningOpt) @@ -439,7 +439,7 @@ func setCounter(tx *Tx, counter int64) { func setFailOnHandler(tx *Tx, fail bool) { for i, msg := range tx.Msgs { - tx.Msgs[i] = msgCounter{msg.(msgCounter).Counter, fail} + tx.Msgs[i] = msgCounter{Counter: msg.(msgCounter).Counter, FailOnHandler: fail} } } @@ -676,8 +676,8 @@ func TestMultiMsgDeliverTx(t *testing.T) { // replace the second message with a msgCounter2 tx = newTxCounter(1, 3) - tx.Msgs = append(tx.Msgs, msgCounter2{0}) - tx.Msgs = append(tx.Msgs, msgCounter2{1}) + tx.Msgs = append(tx.Msgs, msgCounter2{Counter: 0}) + tx.Msgs = append(tx.Msgs, msgCounter2{Counter: 1}) txBytes, err = amino.Marshal(tx) require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) diff --git a/tm2/pkg/store/cache/store_test.go b/tm2/pkg/store/cache/store_test.go index 4ac8cc64de9..1caf51ea52c 100644 --- a/tm2/pkg/store/cache/store_test.go +++ b/tm2/pkg/store/cache/store_test.go @@ -15,7 +15,7 @@ import ( ) func newCacheStore() types.Store { - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} return cache.New(mem) } @@ -25,7 +25,7 @@ func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) } func TestCacheStore(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} st := cache.New(mem) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") @@ -70,7 +70,7 @@ func TestCacheStore(t *testing.T) { func TestCacheStoreNoNilSet(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} st := cache.New(mem) require.Panics(t, func() { st.Set([]byte("key"), nil) }, "setting a nil value should panic") } @@ -78,7 +78,7 @@ func TestCacheStoreNoNilSet(t *testing.T) { func TestCacheStoreNested(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} st := cache.New(mem) // set. check its there on st and not on mem. diff --git a/tm2/pkg/store/gas/store_test.go b/tm2/pkg/store/gas/store_test.go index 5b8cc7c656c..52c8dbf08e8 100644 --- a/tm2/pkg/store/gas/store_test.go +++ b/tm2/pkg/store/gas/store_test.go @@ -20,7 +20,7 @@ func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) } func TestGasKVStoreBasic(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(10000) st := gas.New(mem, meter, types.DefaultGasConfig()) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") @@ -34,7 +34,7 @@ func TestGasKVStoreBasic(t *testing.T) { func TestGasKVStoreIterator(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(10000) st := gas.New(mem, meter, types.DefaultGasConfig()) require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty") @@ -60,7 +60,7 @@ func TestGasKVStoreIterator(t *testing.T) { func TestGasKVStoreOutOfGasSet(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(0) st := gas.New(mem, meter, types.DefaultGasConfig()) require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas") @@ -69,7 +69,7 @@ func TestGasKVStoreOutOfGasSet(t *testing.T) { func TestGasKVStoreOutOfGasIterator(t *testing.T) { t.Parallel() - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} meter := types.NewGasMeter(20000) st := gas.New(mem, meter, types.DefaultGasConfig()) st.Set(keyFmt(1), valFmt(1)) diff --git a/tm2/pkg/store/iavl/store_test.go b/tm2/pkg/store/iavl/store_test.go index 6959e9172dc..9157394cb08 100644 --- a/tm2/pkg/store/iavl/store_test.go +++ b/tm2/pkg/store/iavl/store_test.go @@ -46,7 +46,7 @@ func newAlohaTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, types.CommitID) { } hash, ver, err := tree.SaveVersion() require.Nil(t, err) - return tree, types.CommitID{ver, hash} + return tree, types.CommitID{Version: ver, Hash: hash} } func TestGetImmutable(t *testing.T) { @@ -58,7 +58,7 @@ func TestGetImmutable(t *testing.T) { require.True(t, tree.Set([]byte("hello"), []byte("adios"))) hash, ver, err := tree.SaveVersion() - cID = types.CommitID{ver, hash} + cID = types.CommitID{Version: ver, Hash: hash} require.Nil(t, err) _, err = store.GetImmutable(cID.Version + 1) diff --git a/tm2/pkg/store/prefix/store_test.go b/tm2/pkg/store/prefix/store_test.go index 701ceda17d5..d61b67462e8 100644 --- a/tm2/pkg/store/prefix/store_test.go +++ b/tm2/pkg/store/prefix/store_test.go @@ -106,7 +106,7 @@ func TestPrefixStoreNoNilSet(t *testing.T) { t.Parallel() meter := types.NewGasMeter(100000000) - mem := dbadapter.Store{memdb.NewMemDB()} + mem := dbadapter.Store{DB: memdb.NewMemDB()} gasStore := gas.New(mem, meter, types.DefaultGasConfig()) require.Panics(t, func() { gasStore.Set([]byte("key"), nil) }, "setting a nil value should panic") } @@ -115,7 +115,7 @@ func TestPrefixStoreIterate(t *testing.T) { t.Parallel() db := memdb.NewMemDB() - baseStore := dbadapter.Store{db} + baseStore := dbadapter.Store{DB: db} prefix := []byte("test") prefixStore := New(baseStore, prefix) @@ -165,7 +165,7 @@ func TestPrefixStoreIteratorEdgeCase(t *testing.T) { t.Parallel() db := memdb.NewMemDB() - baseStore := dbadapter.Store{db} + baseStore := dbadapter.Store{DB: db} // overflow in cpIncr prefix := []byte{0xAA, 0xFF, 0xFF} @@ -197,7 +197,7 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { t.Parallel() db := memdb.NewMemDB() - baseStore := dbadapter.Store{db} + baseStore := dbadapter.Store{DB: db} // overflow in cpIncr prefix := []byte{0xAA, 0xFF, 0xFF} @@ -225,7 +225,7 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { iter.Close() db = memdb.NewMemDB() - baseStore = dbadapter.Store{db} + baseStore = dbadapter.Store{DB: db} // underflow in cpDecr prefix = []byte{0xAA, 0x00, 0x00} @@ -256,7 +256,7 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { func mockStoreWithStuff() types.Store { db := memdb.NewMemDB() - store := dbadapter.Store{db} + store := dbadapter.Store{DB: db} // Under "key" prefix store.Set(bz("key"), bz("value")) store.Set(bz("key1"), bz("value1")) From 5444859b159b40927f7771e20cc7386582a87332 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 16 Oct 2024 11:46:26 +0200 Subject: [PATCH 11/64] chore: Remove checkbox with the reminder of adding more Benchmarks. (#2927) --- .github/pull_request_template.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d76f68cba5d..12e07a9cde6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,5 +8,4 @@ - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests -- [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md). From 641d2fd91f03191016f74ea32a0ae9592b884896 Mon Sep 17 00:00:00 2001 From: Jeff Thompson Date: Wed, 16 Oct 2024 14:51:17 +0200 Subject: [PATCH 12/64] feat(tm2/crypto/keys): In the gnokey CLI, add command to update the password (#2700) The `Keybase` API supports a method to [change the password of a key](https://github.com/gnolang/gno/blob/8a62a28f672d3311163bee75f5e8f10ba3d4d52b/tm2/pkg/crypto/keys/keybase.go#L450). It is currently called `Update` which is confusing. This PR renames the API function to `Rotate` and adds the "rotate" command to the gnokey CLI. BREAKING CHANGE: The Keybase API function `Update` is renamed to `Rotate`. (Note: I haven't seen code using this function, so it should be minimal impact.)
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description
--------- Signed-off-by: Jeff Thompson Co-authored-by: Morgan --- .../cli/gnokey/working-with-key-pairs.md | 13 +++ gno.land/pkg/keyscli/root.go | 1 + tm2/pkg/crypto/keys/client/root.go | 1 + tm2/pkg/crypto/keys/client/rotate.go | 75 +++++++++++++++ tm2/pkg/crypto/keys/client/rotate_test.go | 95 +++++++++++++++++++ tm2/pkg/crypto/keys/keybase.go | 4 +- tm2/pkg/crypto/keys/keybase_test.go | 12 +-- tm2/pkg/crypto/keys/lazy_keybase.go | 4 +- tm2/pkg/crypto/keys/types.go | 2 +- 9 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 tm2/pkg/crypto/keys/client/rotate.go create mode 100644 tm2/pkg/crypto/keys/client/rotate_test.go diff --git a/docs/gno-tooling/cli/gnokey/working-with-key-pairs.md b/docs/gno-tooling/cli/gnokey/working-with-key-pairs.md index ba03ca569b4..9bc29da6a18 100644 --- a/docs/gno-tooling/cli/gnokey/working-with-key-pairs.md +++ b/docs/gno-tooling/cli/gnokey/working-with-key-pairs.md @@ -38,6 +38,7 @@ gno.land keychain & client SUBCOMMANDS add adds key to the keybase delete deletes a key from the keybase + rotate rotate the password of a key in the keybase to a new password generate generates a bip39 mnemonic export exports private key armor import imports encrypted private key armor @@ -161,6 +162,18 @@ you can recover it using the key's mnemonic, or by importing it if it was export at a previous point in time. ::: + +## Rotating the password of a private key to a new password +To rotate the password of a private key from the `gnokey` keystore to a new password, we need to know the name or +address of the key to remove. +After we have this information, we can run the following command: + +```bash +gnokey rotate MyKey +``` + +After entering the current key decryption password and the new password, the password of the key will be updated in the keystore. + ## Exporting a private key Private keys stored in the `gnokey` keystore can be exported to a desired place on the user's filesystem. diff --git a/gno.land/pkg/keyscli/root.go b/gno.land/pkg/keyscli/root.go index 19513fc0de6..c910e01b82c 100644 --- a/gno.land/pkg/keyscli/root.go +++ b/gno.land/pkg/keyscli/root.go @@ -30,6 +30,7 @@ func NewRootCmd(io commands.IO, base client.BaseOptions) *commands.Command { cmd.AddSubCommands( client.NewAddCmd(cfg, io), client.NewDeleteCmd(cfg, io), + client.NewRotateCmd(cfg, io), client.NewGenerateCmd(cfg, io), client.NewExportCmd(cfg, io), client.NewImportCmd(cfg, io), diff --git a/tm2/pkg/crypto/keys/client/root.go b/tm2/pkg/crypto/keys/client/root.go index f69155ace85..8dcd9210a50 100644 --- a/tm2/pkg/crypto/keys/client/root.go +++ b/tm2/pkg/crypto/keys/client/root.go @@ -43,6 +43,7 @@ func NewRootCmdWithBaseConfig(io commands.IO, base BaseOptions) *commands.Comman NewExportCmd(cfg, io), NewImportCmd(cfg, io), NewListCmd(cfg, io), + NewRotateCmd(cfg, io), NewSignCmd(cfg, io), NewVerifyCmd(cfg, io), NewQueryCmd(cfg, io), diff --git a/tm2/pkg/crypto/keys/client/rotate.go b/tm2/pkg/crypto/keys/client/rotate.go new file mode 100644 index 00000000000..876e9f40b70 --- /dev/null +++ b/tm2/pkg/crypto/keys/client/rotate.go @@ -0,0 +1,75 @@ +package client + +import ( + "context" + "flag" + "fmt" + + "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/crypto/keys" +) + +type RotateCfg struct { + RootCfg *BaseCfg + + Force bool +} + +func NewRotateCmd(rootCfg *BaseCfg, io commands.IO) *commands.Command { + cfg := &RotateCfg{ + RootCfg: rootCfg, + } + + return commands.NewCommand( + commands.Metadata{ + Name: "rotate", + ShortUsage: "rotate [flags] ", + ShortHelp: "rotate the password of a key in the keybase to a new password", + }, + cfg, + func(_ context.Context, args []string) error { + return execRotate(cfg, args, io) + }, + ) +} + +func (c *RotateCfg) RegisterFlags(fs *flag.FlagSet) { +} + +func execRotate(cfg *RotateCfg, args []string, io commands.IO) error { + if len(args) != 1 { + return flag.ErrHelp + } + + nameOrBech32 := args[0] + + kb, err := keys.NewKeyBaseFromDir(cfg.RootCfg.Home) + if err != nil { + return err + } + + oldpass, err := io.GetPassword("Enter the current password:", cfg.RootCfg.InsecurePasswordStdin) + if err != nil { + return err + } + + newpass, err := io.GetCheckPassword( + [2]string{ + "Enter the new password to encrypt your key to disk:", + "Repeat the password:", + }, + cfg.RootCfg.InsecurePasswordStdin, + ) + if err != nil { + return fmt.Errorf("unable to parse provided password, %w", err) + } + + getNewpass := func() (string, error) { return newpass, nil } + err = kb.Rotate(nameOrBech32, oldpass, getNewpass) + if err != nil { + return err + } + io.ErrPrintln("Password rotated") + + return nil +} diff --git a/tm2/pkg/crypto/keys/client/rotate_test.go b/tm2/pkg/crypto/keys/client/rotate_test.go new file mode 100644 index 00000000000..f365359d943 --- /dev/null +++ b/tm2/pkg/crypto/keys/client/rotate_test.go @@ -0,0 +1,95 @@ +package client + +import ( + "strings" + "testing" + + "github.com/gnolang/gno/tm2/pkg/commands" + "github.com/gnolang/gno/tm2/pkg/crypto/keys" + "github.com/gnolang/gno/tm2/pkg/testutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_execRotate(t *testing.T) { + t.Parallel() + + // make new test dir + kbHome, kbCleanUp := testutils.NewTestCaseDir(t) + defer kbCleanUp() + + // initialize test options + cfg := &RotateCfg{ + RootCfg: &BaseCfg{ + BaseOptions: BaseOptions{ + Home: kbHome, + InsecurePasswordStdin: true, + }, + }, + } + + io := commands.NewTestIO() + + // Add test accounts to keybase. + kb, err := keys.NewKeyBaseFromDir(kbHome) + assert.NoError(t, err) + + keyName := "rotateApp_Key1" + p1, p2 := "1234", "foobar" + mnemonic := "equip will roof matter pink blind book anxiety banner elbow sun young" + + _, err = kb.CreateAccount(keyName, mnemonic, "", p1, 0, 0) + assert.NoError(t, err) + + { + // test: Key not found + args := []string{"blah"} + io.SetIn(strings.NewReader(p1 + "\n" + p2 + "\n" + p2 + "\n")) + err = execRotate(cfg, args, io) + require.Error(t, err) + require.Equal(t, "Key blah not found", err.Error()) + } + + { + // test: Wrong password + args := []string{keyName} + io.SetIn(strings.NewReader("blah" + "\n" + p2 + "\n" + p2 + "\n")) + err = execRotate(cfg, args, io) + require.Error(t, err) + require.Equal(t, "invalid account password", err.Error()) + } + + { + // test: New passwords don't match + args := []string{keyName} + io.SetIn(strings.NewReader(p1 + "\n" + p2 + "\n" + "blah" + "\n")) + err = execRotate(cfg, args, io) + require.Error(t, err) + require.Equal(t, "unable to parse provided password, passphrases don't match", err.Error()) + } + + { + // Rotate the password + args := []string{keyName} + io.SetIn(strings.NewReader(p1 + "\n" + p2 + "\n" + p2 + "\n")) + err = execRotate(cfg, args, io) + require.NoError(t, err) + } + + { + // test: The old password shouldn't work + args := []string{keyName} + io.SetIn(strings.NewReader(p1 + "\n" + p1 + "\n" + p1 + "\n")) + err = execRotate(cfg, args, io) + require.Error(t, err) + require.Equal(t, "invalid account password", err.Error()) + } + + { + // Updating the new password to itself should work + args := []string{keyName} + io.SetIn(strings.NewReader(p2 + "\n" + p2 + "\n" + p2 + "\n")) + err = execRotate(cfg, args, io) + require.NoError(t, err) + } +} diff --git a/tm2/pkg/crypto/keys/keybase.go b/tm2/pkg/crypto/keys/keybase.go index 2dc7d41be0b..c28fd1ef952 100644 --- a/tm2/pkg/crypto/keys/keybase.go +++ b/tm2/pkg/crypto/keys/keybase.go @@ -441,13 +441,13 @@ func (kb dbKeybase) Delete(nameOrBech32, passphrase string, skipPass bool) error return nil } -// Update changes the passphrase with which an already stored key is +// Rotate changes the passphrase with which an already stored key is // encrypted. // // oldpass must be the current passphrase used for encryption, // getNewpass is a function to get the passphrase to permanently replace // the current passphrase -func (kb dbKeybase) Update(nameOrBech32, oldpass string, getNewpass func() (string, error)) error { +func (kb dbKeybase) Rotate(nameOrBech32, oldpass string, getNewpass func() (string, error)) error { info, err := kb.GetByNameOrAddress(nameOrBech32) if err != nil { return err diff --git a/tm2/pkg/crypto/keys/keybase_test.go b/tm2/pkg/crypto/keys/keybase_test.go index 32cc8788b52..afcc1c56197 100644 --- a/tm2/pkg/crypto/keys/keybase_test.go +++ b/tm2/pkg/crypto/keys/keybase_test.go @@ -199,9 +199,9 @@ func assertPassword(t *testing.T, cstore Keybase, name, pass, badpass string) { t.Helper() getNewpass := func() (string, error) { return pass, nil } - err := cstore.Update(name, badpass, getNewpass) + err := cstore.Rotate(name, badpass, getNewpass) require.NotNil(t, err) - err = cstore.Update(name, pass, getNewpass) + err = cstore.Rotate(name, pass, getNewpass) require.Nil(t, err, "%+v", err) } @@ -280,7 +280,7 @@ func TestExportImportPubKey(t *testing.T) { require.NotNil(t, err) } -// TestAdvancedKeyManagement verifies update, import, export functionality +// TestAdvancedKeyManagement verifies rotate, import, export functionality func TestAdvancedKeyManagement(t *testing.T) { t.Parallel() @@ -297,14 +297,14 @@ func TestAdvancedKeyManagement(t *testing.T) { require.Nil(t, err, "%+v", err) assertPassword(t, cstore, n1, p1, p2) - // update password requires the existing password + // rotate password requires the existing password getNewpass := func() (string, error) { return p2, nil } - err = cstore.Update(n1, "jkkgkg", getNewpass) + err = cstore.Rotate(n1, "jkkgkg", getNewpass) require.NotNil(t, err) assertPassword(t, cstore, n1, p1, p2) // then it changes the password when correct - err = cstore.Update(n1, p1, getNewpass) + err = cstore.Rotate(n1, p1, getNewpass) require.NoError(t, err) // p2 is now the proper one! assertPassword(t, cstore, n1, p2, p1) diff --git a/tm2/pkg/crypto/keys/lazy_keybase.go b/tm2/pkg/crypto/keys/lazy_keybase.go index eb9c0f3b551..38cec501135 100644 --- a/tm2/pkg/crypto/keys/lazy_keybase.go +++ b/tm2/pkg/crypto/keys/lazy_keybase.go @@ -179,14 +179,14 @@ func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info Info return NewDBKeybase(db).CreateMulti(name, pubkey) } -func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { +func (lkb lazyKeybase) Rotate(name, oldpass string, getNewpass func() (string, error)) error { db, err := db.NewDB(lkb.name, dbBackend, lkb.dir) if err != nil { return err } defer db.Close() - return NewDBKeybase(db).Update(name, oldpass, getNewpass) + return NewDBKeybase(db).Rotate(name, oldpass, getNewpass) } func (lkb lazyKeybase) Import(name string, armor string) (err error) { diff --git a/tm2/pkg/crypto/keys/types.go b/tm2/pkg/crypto/keys/types.go index c5d33023a0a..3865951168e 100644 --- a/tm2/pkg/crypto/keys/types.go +++ b/tm2/pkg/crypto/keys/types.go @@ -43,7 +43,7 @@ type Keybase interface { CreateMulti(name string, pubkey crypto.PubKey) (info Info, err error) // The following operations will *only* work on locally-stored keys - Update(name, oldpass string, getNewpass func() (string, error)) error + Rotate(name, oldpass string, getNewpass func() (string, error)) error Import(name string, armor string) (err error) ImportPrivKey(name, armor, decryptPassphrase, encryptPassphrase string) error ImportPrivKeyUnsafe(name, armor, encryptPassphrase string) error From 6d986bf39d7f46e7415477584c960e374688f195 Mon Sep 17 00:00:00 2001 From: Sergio Maria Matone Date: Thu, 17 Oct 2024 16:32:58 +0200 Subject: [PATCH 13/64] chore(ci): reducing folders spinning up benchmarks (#2966) Just reduce commits then could trigger benchmarks --- .github/workflows/benchmark-master-push.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index a219a49305a..09978a0ae5c 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -4,6 +4,11 @@ on: push: branches: - master + paths: + - contribs/** + - gno.land/** + - gnovm/** + - tm2/** permissions: # deployments permission to deploy GitHub pages website From 05cd4f5673e9f449bf87264fa40690febb7fee81 Mon Sep 17 00:00:00 2001 From: Morgan Date: Thu, 17 Oct 2024 21:16:18 +0200 Subject: [PATCH 14/64] feat(stdlibs): add package `strconv` (#1464) This PR adds the full `strconv` package, implemented as pure Gno code. It removes the native functions `Itoa` (and others), and adds support for new functions such as `FormatFloat`. # Summary of changes - Standard libraries - Changes of `strconv` from Go stdlib: https://gist.github.com/thehowl/904b42b1ea53fef9b8a0486155c02b73 -- tldr: - removed everything related to complex types. - avoid using reflection and dot imports. - instead of loading testfp.txt, embed the file directly into the source. - define min/max explicitly as they're not built-in yet. - remove go:build tags. - (all of these mostly involve test files.) - `unicode` - Update tables, so that `strconv` tests succeed. - `unicode/utf8` - Update to latest go version. Mostly, use `fallback` (as we now half-support it) and use `AppendString`. - GnoVM - PackageInjector is no longer necessary (hallelujah), see #814 for context. This justifies the changes in `store.go`, `store_test.go`, `nodes.go`, `tests/imports.go`. - `gonative.go` and `machine.go` changes improve some error messages. - `preprocess.go` changes fix a bug which can be seen in the `for20.gno` test. If a `for` loop is labeled, then a bare `break` (ie. without a label to break to) would panic, as it wouldn't find any for loop without a label (in `findBranchLabel`). I added a regression test as well as a couple test showing the error message for when we misplace continue/break statements. - Tests. - `strconv.Itoa` now uses more gas than its existing native implementation. This is to be expected; we can consider moving it back to a native implementation if we deem it useful for performance, but I think it's good for us to work on having as much code implemented directly in gno before moving it back to Go for performance. --------- Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- docs/reference/go-gno-compatibility.md | 4 +- gno.land/cmd/gnoland/testdata/append.txtar | 34 +- .../gnoland/testdata/assertorigincall.txtar | 40 +- .../cmd/gnoland/testdata/grc20_registry.txtar | 10 +- .../cmd/gnoland/testdata/issue_1167.txtar | 12 +- gno.land/cmd/gnoland/testdata/prevrealm.txtar | 28 +- .../testdata/restart_missing_type.txtar | 5 +- gno.land/pkg/gnoclient/integration_test.go | 4 +- .../testdata/loadpkg_example.txtar | 5 +- gnovm/pkg/gnolang/gonative.go | 2 +- gnovm/pkg/gnolang/machine.go | 43 +- gnovm/pkg/gnolang/nodes.go | 1 - gnovm/pkg/gnolang/preprocess.go | 44 +- gnovm/pkg/gnolang/store.go | 47 - gnovm/pkg/gnolang/store_test.go | 1 - gnovm/stdlibs/generated.go | 247 ----- gnovm/stdlibs/strconv/atob.gno | 35 + gnovm/stdlibs/strconv/atob_test.gno | 90 ++ gnovm/stdlibs/strconv/atof.gno | 709 +++++++++++++ gnovm/stdlibs/strconv/atof_test.gno | 774 +++++++++++++++ gnovm/stdlibs/strconv/atoi.gno | 332 +++++++ gnovm/stdlibs/strconv/atoi_test.gno | 677 +++++++++++++ gnovm/stdlibs/strconv/bytealg.gno | 12 + gnovm/stdlibs/strconv/decimal.gno | 415 ++++++++ gnovm/stdlibs/strconv/decimal_test.gno | 126 +++ gnovm/stdlibs/strconv/doc.gno | 59 ++ gnovm/stdlibs/strconv/eisel_lemire.gno | 884 +++++++++++++++++ gnovm/stdlibs/strconv/example_test.gno | 440 ++++++++ gnovm/stdlibs/strconv/export_test.gno | 10 + gnovm/stdlibs/strconv/fp_test.gno | 320 ++++++ gnovm/stdlibs/strconv/ftoa.gno | 584 +++++++++++ gnovm/stdlibs/strconv/ftoa_test.gno | 323 ++++++ gnovm/stdlibs/strconv/ftoaryu.gno | 569 +++++++++++ gnovm/stdlibs/strconv/ftoaryu_test.gno | 30 + gnovm/stdlibs/strconv/internal_test.gno | 31 + gnovm/stdlibs/strconv/isprint.gno | 752 ++++++++++++++ gnovm/stdlibs/strconv/itoa.gno | 205 ++++ gnovm/stdlibs/strconv/itoa_test.gno | 242 +++++ gnovm/stdlibs/strconv/quote.gno | 599 +++++++++++ gnovm/stdlibs/strconv/quote_test.gno | 383 +++++++ gnovm/stdlibs/strconv/strconv.gno | 10 - gnovm/stdlibs/strconv/strconv.go | 12 - gnovm/stdlibs/strconv/strconv_test.gno | 156 +++ gnovm/stdlibs/unicode/example_test.gno | 64 +- gnovm/stdlibs/unicode/letter.gno | 2 +- gnovm/stdlibs/unicode/tables.gno | 938 ++++++++++++------ gnovm/stdlibs/unicode/utf8/example_test.gno | 11 + gnovm/stdlibs/unicode/utf8/utf8.gno | 55 +- gnovm/stdlibs/unicode/utf8/utf8_test.gno | 11 + gnovm/tests/files/break0.gno | 8 + gnovm/tests/files/cont3.gno | 8 + gnovm/tests/files/for20.gno | 15 + gnovm/tests/files/redeclaration10.gno | 4 +- gnovm/tests/files/redeclaration6.gno | 4 +- gnovm/tests/files/redeclaration8.gno | 4 +- gnovm/tests/imports.go | 23 +- 56 files changed, 9703 insertions(+), 750 deletions(-) create mode 100644 gnovm/stdlibs/strconv/atob.gno create mode 100644 gnovm/stdlibs/strconv/atob_test.gno create mode 100644 gnovm/stdlibs/strconv/atof.gno create mode 100644 gnovm/stdlibs/strconv/atof_test.gno create mode 100644 gnovm/stdlibs/strconv/atoi.gno create mode 100644 gnovm/stdlibs/strconv/atoi_test.gno create mode 100644 gnovm/stdlibs/strconv/bytealg.gno create mode 100644 gnovm/stdlibs/strconv/decimal.gno create mode 100644 gnovm/stdlibs/strconv/decimal_test.gno create mode 100644 gnovm/stdlibs/strconv/doc.gno create mode 100644 gnovm/stdlibs/strconv/eisel_lemire.gno create mode 100644 gnovm/stdlibs/strconv/example_test.gno create mode 100644 gnovm/stdlibs/strconv/export_test.gno create mode 100644 gnovm/stdlibs/strconv/fp_test.gno create mode 100644 gnovm/stdlibs/strconv/ftoa.gno create mode 100644 gnovm/stdlibs/strconv/ftoa_test.gno create mode 100644 gnovm/stdlibs/strconv/ftoaryu.gno create mode 100644 gnovm/stdlibs/strconv/ftoaryu_test.gno create mode 100644 gnovm/stdlibs/strconv/internal_test.gno create mode 100644 gnovm/stdlibs/strconv/isprint.gno create mode 100644 gnovm/stdlibs/strconv/itoa.gno create mode 100644 gnovm/stdlibs/strconv/itoa_test.gno create mode 100644 gnovm/stdlibs/strconv/quote.gno create mode 100644 gnovm/stdlibs/strconv/quote_test.gno delete mode 100644 gnovm/stdlibs/strconv/strconv.gno delete mode 100644 gnovm/stdlibs/strconv/strconv.go create mode 100644 gnovm/stdlibs/strconv/strconv_test.gno create mode 100644 gnovm/tests/files/break0.gno create mode 100644 gnovm/tests/files/cont3.gno create mode 100644 gnovm/tests/files/for20.gno diff --git a/docs/reference/go-gno-compatibility.md b/docs/reference/go-gno-compatibility.md index bad19860655..f73ff33cce7 100644 --- a/docs/reference/go-gno-compatibility.md +++ b/docs/reference/go-gno-compatibility.md @@ -248,7 +248,7 @@ Legend: | runtime/trace | `gospec` | | slices | `gnics` | | sort | `part`[^6] | -| strconv | `part` | +| strconv | `full`[^10] | | strings | `full` | | sync | `tbd` | | sync/atomic | `tbd` | @@ -292,6 +292,8 @@ Legend: [^8]: `crypto/ed25519` is currently only implemented for `Verify`, which should still cover a majority of use cases. A full implementation is welcome. [^9]: `math/rand` in Gno ports over Go's `math/rand/v2`. +[^10]: `strconv` does not have the methods relating to types `complex64` and + `complex128`. ## Tooling (`gno` binary) diff --git a/gno.land/cmd/gnoland/testdata/append.txtar b/gno.land/cmd/gnoland/testdata/append.txtar index 46b66f9524b..3450b3e9b32 100644 --- a/gno.land/cmd/gnoland/testdata/append.txtar +++ b/gno.land/cmd/gnoland/testdata/append.txtar @@ -3,69 +3,69 @@ loadpkg gno.land/p/demo/ufmt # start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/append -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/append -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 1 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '1' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '1' -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func AppendNil -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func AppendNil -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 2 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '2' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '2' -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 3 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '3' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '3' -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("1-2-3-" string)' stdout OK! # Call Pop -gnokey maketx call -pkgpath gno.land/r/append -func Pop -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Pop -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-" string)' stdout OK! # Call Append 42 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '42' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '42' -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func CopyAppend -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func CopyAppend -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func PopB -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func PopB -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func AppendMoreAndC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func AppendMoreAndC -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func ReassignC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func ReassignC -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-70-100-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'd' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args 'd' -broadcast -chainid=tendermint_test test1 stdout '("1-" string)' stdout OK! diff --git a/gno.land/cmd/gnoland/testdata/assertorigincall.txtar b/gno.land/cmd/gnoland/testdata/assertorigincall.txtar index e3cd1be744a..1315f23cc95 100644 --- a/gno.land/cmd/gnoland/testdata/assertorigincall.txtar +++ b/gno.land/cmd/gnoland/testdata/assertorigincall.txtar @@ -33,85 +33,85 @@ gnoland start # Test cases ## 1. MsgCall -> myrlm.A: PANIC -! gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +! gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stderr 'invalid non-origin call' ## 2. MsgCall -> myrlm.B: PASS -gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 3. MsgCall -> myrlm.C: PASS -gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 4. MsgCall -> r/foo.A -> myrlm.A: PANIC -! gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +! gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stderr 'invalid non-origin call' ## 5. MsgCall -> r/foo.B -> myrlm.B: PASS -gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 6. MsgCall -> r/foo.C -> myrlm.C: PANIC -! gnokey maketx call -pkgpath gno.land/r/foo -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +! gnokey maketx call -pkgpath gno.land/r/foo -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stderr 'invalid non-origin call' ## remove due to update to maketx call can only call realm (case 7,8,9) ## 7. MsgCall -> p/demo/bar.A -> myrlm.A: PANIC -## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stderr 'invalid non-origin call' ## 8. MsgCall -> p/demo/bar.B -> myrlm.B: PASS -## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout 'OK!' ## 9. MsgCall -> p/demo/bar.C -> myrlm.C: PANIC -## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stderr 'invalid non-origin call' ## 10. MsgRun -> run.main -> myrlm.A: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno stderr 'invalid non-origin call' ## 11. MsgRun -> run.main -> myrlm.B: PASS -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno stdout 'OK!' ## 12. MsgRun -> run.main -> myrlm.C: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmC.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmC.gno stderr 'invalid non-origin call' ## 13. MsgRun -> run.main -> foo.A: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno stderr 'invalid non-origin call' ## 14. MsgRun -> run.main -> foo.B: PASS -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno stdout 'OK!' ## 15. MsgRun -> run.main -> foo.C: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooC.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooC.gno stderr 'invalid non-origin call' ## 16. MsgRun -> run.main -> bar.A: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno stderr 'invalid non-origin call' ## 17. MsgRun -> run.main -> bar.B: PASS -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno stdout 'OK!' ## 18. MsgRun -> run.main -> bar.C: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barC.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barC.gno stderr 'invalid non-origin call' ## remove testcase 19 due to maketx call forced to call a realm ## 19. MsgCall -> std.AssertOriginCall: pass -## gnokey maketx call -pkgpath std -func AssertOriginCall -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath std -func AssertOriginCall -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout 'OK!' ## 20. MsgRun -> std.AssertOriginCall: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno stderr 'invalid non-origin call' diff --git a/gno.land/cmd/gnoland/testdata/grc20_registry.txtar b/gno.land/cmd/gnoland/testdata/grc20_registry.txtar index 20e78f7ba6e..a5f7ad5eee3 100644 --- a/gno.land/cmd/gnoland/testdata/grc20_registry.txtar +++ b/gno.land/cmd/gnoland/testdata/grc20_registry.txtar @@ -6,15 +6,15 @@ loadpkg gno.land/r/registry $WORK/registry gnoland start # we call Transfer with foo20, before it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout 'not found' # add foo20, and foo20wrapper -gnokey maketx addpkg -pkgdir $WORK/foo20 -pkgpath gno.land/r/foo20 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -pkgpath gno.land/r/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/foo20 -pkgpath gno.land/r/foo20 -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -pkgpath gno.land/r/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 # we call Transfer with foo20, after it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout 'same address, success!' -- registry/registry.gno -- @@ -49,7 +49,7 @@ import "gno.land/r/registry" import "gno.land/r/foo20" func init() { - registry.Register("foo20", foo20.Transfer) + registry.Register("foo20", foo20.Transfer) } -- foo20/foo20.gno -- diff --git a/gno.land/cmd/gnoland/testdata/issue_1167.txtar b/gno.land/cmd/gnoland/testdata/issue_1167.txtar index c43f7a45bd5..73febb0235a 100644 --- a/gno.land/cmd/gnoland/testdata/issue_1167.txtar +++ b/gno.land/cmd/gnoland/testdata/issue_1167.txtar @@ -4,30 +4,30 @@ loadpkg gno.land/p/demo/avl gnoland start # add contract -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/xx -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/xx -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # execute New -gnokey maketx call -pkgpath gno.land/r/demo/xx -func New -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func New -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # execute Delta for the first time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '"1,1,1;" string' # execute Delta for the second time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;" string' # execute Delta for the third time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;3,3,3;" string' # execute Render -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Render -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Render -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;3,3,3;" string' diff --git a/gno.land/cmd/gnoland/testdata/prevrealm.txtar b/gno.land/cmd/gnoland/testdata/prevrealm.txtar index 72a207fae22..7a0d994a686 100644 --- a/gno.land/cmd/gnoland/testdata/prevrealm.txtar +++ b/gno.land/cmd/gnoland/testdata/prevrealm.txtar @@ -34,60 +34,60 @@ env RFOO_ADDR=g1evezrh92xaucffmtgsaa3rvmz5s8kedffsg469 # Test cases ## 1. MsgCall -> myrlm.A: user address -gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${USER_ADDR_test1} ## 2. MsgCall -> myrealm.B -> myrlm.A: user address -gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${USER_ADDR_test1} ## 3. MsgCall -> r/foo.A -> myrlm.A: r/foo -gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${RFOO_ADDR} ## 4. MsgCall -> r/foo.B -> myrlm.B -> r/foo.A: r/foo -gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${RFOO_ADDR} ## remove due to update to maketx call can only call realm (case 5, 6, 13) ## 5. MsgCall -> p/demo/bar.A -> myrlm.A: user address -## gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout ${USER_ADDR_test1} ## 6. MsgCall -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address -## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout ${USER_ADDR_test1} ## 7. MsgRun -> myrlm.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno stdout ${USER_ADDR_test1} ## 8. MsgRun -> myrealm.B -> myrlm.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno stdout ${USER_ADDR_test1} ## 9. MsgRun -> r/foo.A -> myrlm.A: r/foo -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno stdout ${RFOO_ADDR} ## 10. MsgRun -> r/foo.B -> myrlm.B -> r/foo.A: r/foo -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno stdout ${RFOO_ADDR} ## 11. MsgRun -> p/demo/bar.A -> myrlm.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno stdout ${USER_ADDR_test1} ## 12. MsgRun -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno stdout ${USER_ADDR_test1} ## 13. MsgCall -> std.PrevRealm(): user address -## gnokey maketx call -pkgpath std -func PrevRealm -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath std -func PrevRealm -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout ${USER_ADDR_test1} ## 14. MsgRun -> std.PrevRealm(): user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno stdout ${USER_ADDR_test1} -- r/myrlm/myrlm.gno -- diff --git a/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar b/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar index 7eb91096437..c492f1c6646 100644 --- a/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar +++ b/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar @@ -162,7 +162,7 @@ gnoland restart } ], "fee": { - "gas_wanted": "16000000", + "gas_wanted": "20000000", "gas_fee": "1000000ugnot" }, "signatures": [], @@ -193,10 +193,9 @@ gnoland restart } ], "fee": { - "gas_wanted": "15000000", + "gas_wanted": "16000000", "gas_fee": "1000000ugnot" }, "signatures": [], "memo": "" } - diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index ea068e0680b..846962766f8 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -359,7 +359,7 @@ func TestRunMultiple_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ GasFee: ugnot.ValueString(10000), - GasWanted: 8000000, + GasWanted: 13000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", @@ -556,7 +556,7 @@ func Echo(str string) string { body2 := `package hello func Hello(str string) string { - return "Hello " + str + "!" + return "Hello " + str + "!" }` caller, err := client.Signer.Info() diff --git a/gno.land/pkg/integration/testdata/loadpkg_example.txtar b/gno.land/pkg/integration/testdata/loadpkg_example.txtar index d0c95331ff5..9dccd72c8a6 100644 --- a/gno.land/pkg/integration/testdata/loadpkg_example.txtar +++ b/gno.land/pkg/integration/testdata/loadpkg_example.txtar @@ -4,11 +4,11 @@ loadpkg gno.land/p/demo/ufmt ## start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/importtest -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/importtest -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! ## execute Render -gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("92054" string)' stdout OK! @@ -25,4 +25,3 @@ import ( func Render(_ string) string { return ufmt.Sprintf("%d", 92054) } - diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 6127fa42b07..0676854aa39 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -866,7 +866,7 @@ func gno2GoType(t Type) reflect.Type { return rt } else { // NOTE: can this be implemented in go1.15? i think not. - panic("not yet supported") + panic("gno2go conversion of type not yet supported: " + ct.String()) } case *TypeType: panic("should not happen") diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index a0542bf9713..ad94f1a2b3a 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -8,6 +8,8 @@ import ( "io" "os" "reflect" + "slices" + "strconv" "strings" "sync" "testing" @@ -278,8 +280,10 @@ func (m *Machine) RunMemPackageWithOverrides(memPkg *std.MemPackage, save bool) func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (*PackageNode, *PackageValue) { // parse files. files := ParseMemPackage(memPkg) - if !overrides && checkDuplicates(files) { - panic(fmt.Errorf("running package %q: duplicate declarations not allowed", memPkg.Path)) + if !overrides { + if err := checkDuplicates(files); err != nil { + panic(fmt.Errorf("running package %q: %w", memPkg.Path, err)) + } } // make and set package if doesn't exist. pn := (*PackageNode)(nil) @@ -322,9 +326,31 @@ func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (* return pn, pv } -// checkDuplicates returns true if there duplicate declarations in the fset. -func checkDuplicates(fset *FileSet) bool { +type redeclarationErrors []Name + +func (r redeclarationErrors) Error() string { + var b strings.Builder + b.WriteString("redeclarations for identifiers: ") + for idx, s := range r { + b.WriteString(strconv.Quote(string(s))) + if idx != len(r)-1 { + b.WriteString(", ") + } + } + return b.String() +} + +func (r redeclarationErrors) add(newI Name) redeclarationErrors { + if slices.Contains(r, newI) { + return r + } + return append(r, newI) +} + +// checkDuplicates returns an error if there are duplicate declarations in the fset. +func checkDuplicates(fset *FileSet) error { defined := make(map[Name]struct{}, 128) + var duplicated redeclarationErrors for _, f := range fset.Files { for _, d := range f.Decls { var name Name @@ -345,7 +371,7 @@ func checkDuplicates(fset *FileSet) bool { continue } if _, ok := defined[nx.Name]; ok { - return true + duplicated = duplicated.add(nx.Name) } defined[nx.Name] = struct{}{} } @@ -357,12 +383,15 @@ func checkDuplicates(fset *FileSet) bool { continue } if _, ok := defined[name]; ok { - return true + duplicated = duplicated.add(name) } defined[name] = struct{}{} } } - return false + if len(duplicated) > 0 { + return duplicated + } + return nil } func destar(x Expr) Expr { diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 8927eafcfb2..5f5e8bd30b9 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -2118,7 +2118,6 @@ const ( ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" ATTR_IOTA GnoAttribute = "ATTR_IOTA" ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED" - ATTR_INJECTED GnoAttribute = "ATTR_INJECTED" ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" ) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index df1f7bab498..61096626f28 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2104,14 +2104,28 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { case *BranchStmt: switch n.Op { case BREAK: - if !isSwitchLabel(ns, n.Label) { - findBranchLabel(last, n.Label) + if n.Label == "" { + if !findBreakableNode(ns) { + panic("cannot break with no parent loop or switch") + } + } else { + // Make sure that the label exists, either for a switch or a + // BranchStmt. + if !isSwitchLabel(ns, n.Label) { + findBranchLabel(last, n.Label) + } } case CONTINUE: - if isSwitchLabel(ns, n.Label) { - panic(fmt.Sprintf("invalid continue label %q\n", n.Label)) + if n.Label == "" { + if !findContinuableNode(ns) { + panic("cannot continue with no parent loop") + } + } else { + if isSwitchLabel(ns, n.Label) { + panic(fmt.Sprintf("invalid continue label %q\n", n.Label)) + } + findBranchLabel(last, n.Label) } - findBranchLabel(last, n.Label) case GOTO: _, depth, index := findGotoLabel(last, n.Label) n.Depth = depth @@ -2775,6 +2789,26 @@ func funcOf(last BlockNode) (BlockNode, *FuncTypeExpr) { } } +func findBreakableNode(ns []Node) bool { + for _, n := range ns { + switch n.(type) { + case *ForStmt, *RangeStmt, *SwitchClauseStmt: + return true + } + } + return false +} + +func findContinuableNode(ns []Node) bool { + for _, n := range ns { + switch n.(type) { + case *ForStmt, *RangeStmt: + return true + } + } + return false +} + func findBranchLabel(last BlockNode, label Name) ( bn BlockNode, depth uint8, bodyIdx int, ) { diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 8a1743ddf53..0e6d89a7bf3 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -25,9 +25,6 @@ import ( // cause writes to happen to the store, such as MemPackages to iavlstore. type PackageGetter func(pkgPath string, store Store) (*PackageNode, *PackageValue) -// inject natives into a new or loaded package (value and node) -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) @@ -66,7 +63,6 @@ type Store interface { GetMemFile(path string, name string) *std.MemFile IterMemPackage() <-chan *std.MemPackage ClearObjectCache() // run before processing a message - SetPackageInjector(PackageInjector) // for natives SetNativeStore(NativeStore) // for "new" natives XXX GetNative(pkgPath string, name Name) func(m *Machine) // for "new" natives XXX SetLogStoreOps(enabled bool) @@ -101,7 +97,6 @@ type defaultStore struct { // store configuration; cannot be modified in a transaction pkgGetter PackageGetter // non-realm packages cacheNativeTypes map[reflect.Type]Type // reflect doc: reflect.Type are comparable - pkgInjector PackageInjector // for injecting natives nativeStore NativeStore // for injecting natives go2gnoStrict bool // if true, native->gno type conversion must be registered. @@ -124,7 +119,6 @@ func NewStore(alloc *Allocator, baseStore, iavlStore store.Store) *defaultStore // store configuration pkgGetter: nil, cacheNativeTypes: make(map[reflect.Type]Type), - pkgInjector: nil, nativeStore: nil, go2gnoStrict: true, } @@ -154,7 +148,6 @@ func (ds *defaultStore) BeginTransaction(baseStore, iavlStore store.Store) Trans // store configuration pkgGetter: ds.pkgGetter, cacheNativeTypes: ds.cacheNativeTypes, - pkgInjector: ds.pkgInjector, nativeStore: ds.nativeStore, go2gnoStrict: ds.go2gnoStrict, @@ -190,10 +183,6 @@ func (transactionStore) ClearCache() { // 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") } @@ -263,26 +252,6 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue rlm := ds.GetPackageRealm(pkgPath) pv.Realm = rlm } - // get package node. - pl := PackageNodeLocation(pkgPath) - pn, ok := ds.GetBlockNodeSafe(pl).(*PackageNode) - if !ok { - // Do not inject packages from packageGetter - // that don't have corresponding *PackageNodes. - } else { - // Inject natives after load. - if ds.pkgInjector != nil { - if pn.HasAttribute(ATTR_INJECTED) { - // e.g. in checktx or simulate or query. - pn.PrepareNewValues(pv) - } else { - // pv.GetBlock(ds) // preload pv.Block - ds.pkgInjector(ds, pn) - pn.SetAttribute(ATTR_INJECTED, true) - pn.PrepareNewValues(pv) - } - } - } // Rederive pv.fBlocksMap. pv.deriveFBlocksMap(ds) return pv @@ -303,18 +272,6 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue // will get written elsewhere // later. ds.cacheObjects[oid] = pv - // inject natives after init. - if ds.pkgInjector != nil { - if pn.HasAttribute(ATTR_INJECTED) { - // not sure why this would happen. - panic("should not happen") - // pn.PrepareNewValues(pv) - } else { - ds.pkgInjector(ds, pn) - pn.SetAttribute(ATTR_INJECTED, true) - pn.PrepareNewValues(pv) - } - } // cache all types. usually preprocess() sets types, // but packages gotten from the pkgGetter may skip this step, // so fill in store.CacheTypes here. @@ -742,10 +699,6 @@ func (ds *defaultStore) ClearObjectCache() { ds.SetCachePackage(Uverse()) } -func (ds *defaultStore) SetPackageInjector(inj PackageInjector) { - ds.pkgInjector = inj -} - func (ds *defaultStore) SetNativeStore(ns NativeStore) { ds.nativeStore = ns } diff --git a/gnovm/pkg/gnolang/store_test.go b/gnovm/pkg/gnolang/store_test.go index 8114291d1b6..17f55993705 100644 --- a/gnovm/pkg/gnolang/store_test.go +++ b/gnovm/pkg/gnolang/store_test.go @@ -59,7 +59,6 @@ func TestTransactionStore_blockedMethods(t *testing.T) { // 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) }) } diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 4c460e220b7..7693e9d6e70 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -11,7 +11,6 @@ import ( libs_crypto_sha256 "github.com/gnolang/gno/gnovm/stdlibs/crypto/sha256" libs_math "github.com/gnolang/gno/gnovm/stdlibs/math" libs_std "github.com/gnolang/gno/gnovm/stdlibs/std" - libs_strconv "github.com/gnolang/gno/gnovm/stdlibs/strconv" libs_testing "github.com/gnolang/gno/gnovm/stdlibs/testing" libs_time "github.com/gnolang/gno/gnovm/stdlibs/time" ) @@ -721,252 +720,6 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, - { - "strconv", - "Itoa", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 int - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.Itoa(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "AppendUint", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("[]byte")}, - {Name: gno.N("p1"), Type: gno.X("uint64")}, - {Name: gno.N("p2"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]byte")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 []byte - rp0 = reflect.ValueOf(&p0).Elem() - p1 uint64 - rp1 = reflect.ValueOf(&p1).Elem() - p2 int - rp2 = reflect.ValueOf(&p2).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 2, "")).TV, rp2) - - r0 := libs_strconv.AppendUint(p0, p1, p2) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "Atoi", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int")}, - {Name: gno.N("r1"), Type: gno.X("error")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0, r1 := libs_strconv.Atoi(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r1).Elem(), - )) - }, - }, - { - "strconv", - "CanBackquote", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.CanBackquote(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "FormatInt", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int64")}, - {Name: gno.N("p1"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 int64 - rp0 = reflect.ValueOf(&p0).Elem() - p1 int - rp1 = reflect.ValueOf(&p1).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - - r0 := libs_strconv.FormatInt(p0, p1) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "FormatUint", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint64")}, - {Name: gno.N("p1"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 uint64 - rp0 = reflect.ValueOf(&p0).Elem() - p1 int - rp1 = reflect.ValueOf(&p1).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - - r0 := libs_strconv.FormatUint(p0, p1) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "Quote", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.Quote(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "QuoteToASCII", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.QuoteToASCII(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, { "testing", "unixNano", diff --git a/gnovm/stdlibs/strconv/atob.gno b/gnovm/stdlibs/strconv/atob.gno new file mode 100644 index 00000000000..0a495008d77 --- /dev/null +++ b/gnovm/stdlibs/strconv/atob.gno @@ -0,0 +1,35 @@ +// 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 strconv + +// ParseBool returns the boolean value represented by the string. +// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. +// Any other value returns an error. +func ParseBool(str string) (bool, error) { + switch str { + case "1", "t", "T", "true", "TRUE", "True": + return true, nil + case "0", "f", "F", "false", "FALSE", "False": + return false, nil + } + return false, syntaxError("ParseBool", str) +} + +// FormatBool returns "true" or "false" according to the value of b. +func FormatBool(b bool) string { + if b { + return "true" + } + return "false" +} + +// AppendBool appends "true" or "false", according to the value of b, +// to dst and returns the extended buffer. +func AppendBool(dst []byte, b bool) []byte { + if b { + return append(dst, "true"...) + } + return append(dst, "false"...) +} diff --git a/gnovm/stdlibs/strconv/atob_test.gno b/gnovm/stdlibs/strconv/atob_test.gno new file mode 100644 index 00000000000..39746f8953d --- /dev/null +++ b/gnovm/stdlibs/strconv/atob_test.gno @@ -0,0 +1,90 @@ +// 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 strconv + +import ( + "bytes" + "testing" +) + +type atobTest struct { + in string + out bool + err error +} + +var atobtests = []atobTest{ + {"", false, ErrSyntax}, + {"asdf", false, ErrSyntax}, + {"0", false, nil}, + {"f", false, nil}, + {"F", false, nil}, + {"FALSE", false, nil}, + {"false", false, nil}, + {"False", false, nil}, + {"1", true, nil}, + {"t", true, nil}, + {"T", true, nil}, + {"TRUE", true, nil}, + {"true", true, nil}, + {"True", true, nil}, +} + +func TestParseBool(t *testing.T) { + for _, test := range atobtests { + b, e := ParseBool(test.in) + if test.err != nil { + // expect an error + if e == nil { + t.Errorf("ParseBool(%s) = nil; want %s", test.in, test.err) + } else { + // NumError assertion must succeed; it's the only thing we return. + if e.(*NumError).Err != test.err { + t.Errorf("ParseBool(%s) = %s; want %s", test.in, e, test.err) + } + } + } else { + if e != nil { + t.Errorf("ParseBool(%s) = %s; want nil", test.in, e) + } + if b != test.out { + t.Errorf("ParseBool(%s) = %t; want %t", test.in, b, test.out) + } + } + } +} + +var boolString = map[bool]string{ + true: "true", + false: "false", +} + +func TestFormatBool(t *testing.T) { + for b, s := range boolString { + if f := FormatBool(b); f != s { + t.Errorf("FormatBool(%v) = %q; want %q", b, f, s) + } + } +} + +type appendBoolTest struct { + b bool + in []byte + out []byte +} + +var appendBoolTests = []appendBoolTest{ + {true, []byte("foo "), []byte("foo true")}, + {false, []byte("foo "), []byte("foo false")}, +} + +func TestAppendBool(t *testing.T) { + for _, test := range appendBoolTests { + b := AppendBool(test.in, test.b) + if !bytes.Equal(b, test.out) { + t.Errorf("AppendBool(%q, %v) = %q; want %q", test.in, test.b, b, test.out) + } + } +} diff --git a/gnovm/stdlibs/strconv/atof.gno b/gnovm/stdlibs/strconv/atof.gno new file mode 100644 index 00000000000..8fc90425f69 --- /dev/null +++ b/gnovm/stdlibs/strconv/atof.gno @@ -0,0 +1,709 @@ +// 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 strconv + +// decimal to binary floating point conversion. +// Algorithm: +// 1) Store input in multiprecision decimal. +// 2) Multiply/divide decimal by powers of two until in range [0.5, 1) +// 3) Multiply by 2^precision and round to get mantissa. + +import "math" + +var optimize = true // set to false to force slow-path conversions for testing + +// commonPrefixLenIgnoreCase returns the length of the common +// prefix of s and prefix, with the character case of s ignored. +// The prefix argument must be all lower-case. +func commonPrefixLenIgnoreCase(s, prefix string) int { + n := len(prefix) + if n > len(s) { + n = len(s) + } + for i := 0; i < n; i++ { + c := s[i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + if c != prefix[i] { + return i + } + } + return n +} + +// special returns the floating-point value for the special, +// possibly signed floating-point representations inf, infinity, +// and NaN. The result is ok if a prefix of s contains one +// of these representations and n is the length of that prefix. +// The character case is ignored. +func special(s string) (f float64, n int, ok bool) { + if len(s) == 0 { + return 0, 0, false + } + sign := 1 + nsign := 0 + switch s[0] { + case '+', '-': + if s[0] == '-' { + sign = -1 + } + nsign = 1 + s = s[1:] + fallthrough + case 'i', 'I': + n := commonPrefixLenIgnoreCase(s, "infinity") + // Anything longer than "inf" is ok, but if we + // don't have "infinity", only consume "inf". + if 3 < n && n < 8 { + n = 3 + } + if n == 3 || n == 8 { + return math.Inf(sign), nsign + n, true + } + case 'n', 'N': + if commonPrefixLenIgnoreCase(s, "nan") == 3 { + return math.NaN(), 3, true + } + } + return 0, 0, false +} + +func (b *decimal) set(s string) (ok bool) { + i := 0 + b.neg = false + b.trunc = false + + // optional sign + if i >= len(s) { + return + } + switch { + case s[i] == '+': + i++ + case s[i] == '-': + b.neg = true + i++ + } + + // digits + sawdot := false + sawdigits := false + for ; i < len(s); i++ { + switch { + case s[i] == '_': + // readFloat already checked underscores + continue + case s[i] == '.': + if sawdot { + return + } + sawdot = true + b.dp = b.nd + continue + + case '0' <= s[i] && s[i] <= '9': + sawdigits = true + if s[i] == '0' && b.nd == 0 { // ignore leading zeros + b.dp-- + continue + } + if b.nd < len(b.d) { + b.d[b.nd] = s[i] + b.nd++ + } else if s[i] != '0' { + b.trunc = true + } + continue + } + break + } + if !sawdigits { + return + } + if !sawdot { + b.dp = b.nd + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && lower(s[i]) == 'e' { + i++ + if i >= len(s) { + return + } + esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + return + } + e := 0 + for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + // readFloat already checked underscores + continue + } + if e < 10000 { + e = e*10 + int(s[i]) - '0' + } + } + b.dp += e * esign + } + + if i != len(s) { + return + } + + ok = true + return +} + +// readFloat reads a decimal or hexadecimal mantissa and exponent from a float +// string representation in s; the number may be followed by other characters. +// readFloat reports the number of bytes consumed (i), and whether the number +// is valid (ok). +func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex bool, i int, ok bool) { + underscores := false + + // optional sign + if i >= len(s) { + return + } + switch { + case s[i] == '+': + i++ + case s[i] == '-': + neg = true + i++ + } + + // digits + base := uint64(10) + maxMantDigits := 19 // 10^19 fits in uint64 + expChar := byte('e') + if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' { + base = 16 + maxMantDigits = 16 // 16^16 fits in uint64 + i += 2 + expChar = 'p' + hex = true + } + sawdot := false + sawdigits := false + nd := 0 + ndMant := 0 + dp := 0 +loop: + for ; i < len(s); i++ { + switch c := s[i]; true { + case c == '_': + underscores = true + continue + + case c == '.': + if sawdot { + break loop + } + sawdot = true + dp = nd + continue + + case '0' <= c && c <= '9': + sawdigits = true + if c == '0' && nd == 0 { // ignore leading zeros + dp-- + continue + } + nd++ + if ndMant < maxMantDigits { + mantissa *= base + mantissa += uint64(c - '0') + ndMant++ + } else if c != '0' { + trunc = true + } + continue + + case base == 16 && 'a' <= lower(c) && lower(c) <= 'f': + sawdigits = true + nd++ + if ndMant < maxMantDigits { + mantissa *= 16 + mantissa += uint64(lower(c) - 'a' + 10) + ndMant++ + } else { + trunc = true + } + continue + } + break + } + if !sawdigits { + return + } + if !sawdot { + dp = nd + } + + if base == 16 { + dp *= 4 + ndMant *= 4 + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && lower(s[i]) == expChar { + i++ + if i >= len(s) { + return + } + esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + return + } + e := 0 + for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + underscores = true + continue + } + if e < 10000 { + e = e*10 + int(s[i]) - '0' + } + } + dp += e * esign + } else if base == 16 { + // Must have exponent. + return + } + + if mantissa != 0 { + exp = dp - ndMant + } + + if underscores && !underscoreOK(s[:i]) { + return + } + + ok = true + return +} + +// decimal power of ten to binary power of two. +var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26} + +func (d *decimal) floatBits(flt *floatInfo) (b uint64, overflow bool) { + var exp int + var mant uint64 + + // Zero is always a special case. + if d.nd == 0 { + mant = 0 + exp = flt.bias + goto out + } + + // Obvious overflow/underflow. + // These bounds are for 64-bit floats. + // Will have to change if we want to support 80-bit floats in the future. + if d.dp > 310 { + goto overflow + } + if d.dp < -330 { + // zero + mant = 0 + exp = flt.bias + goto out + } + + // Scale by powers of two until in range [0.5, 1.0) + exp = 0 + for d.dp > 0 { + var n int + if d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[d.dp] + } + d.Shift(-n) + exp += n + } + for d.dp < 0 || d.dp == 0 && d.d[0] < '5' { + var n int + if -d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[-d.dp] + } + d.Shift(n) + exp -= n + } + + // Our range is [0.5,1) but floating point range is [1,2). + exp-- + + // Minimum representable exponent is flt.bias+1. + // If the exponent is smaller, move it up and + // adjust d accordingly. + if exp < flt.bias+1 { + n := flt.bias + 1 - exp + d.Shift(-n) + exp += n + } + + if exp-flt.bias >= 1<>= 1 + exp++ + if exp-flt.bias >= 1<>float64info.mantbits != 0 { + return + } + f = float64(mantissa) + if neg { + f = -f + } + switch { + case exp == 0: + // an integer. + return f, true + // Exact integers are <= 10^15. + // Exact powers of ten are <= 10^22. + case exp > 0 && exp <= 15+22: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 22 { + f *= float64pow10[exp-22] + exp = 22 + } + if f > 1e15 || f < -1e15 { + // the exponent was really too large. + return + } + return f * float64pow10[exp], true + case exp < 0 && exp >= -22: // int / 10^k + return f / float64pow10[-exp], true + } + return +} + +// If possible to compute mantissa*10^exp to 32-bit float f exactly, +// entirely in floating-point math, do so, avoiding the machinery above. +func atof32exact(mantissa uint64, exp int, neg bool) (f float32, ok bool) { + if mantissa>>float32info.mantbits != 0 { + return + } + f = float32(mantissa) + if neg { + f = -f + } + switch { + case exp == 0: + return f, true + // Exact integers are <= 10^7. + // Exact powers of ten are <= 10^10. + case exp > 0 && exp <= 7+10: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 10 { + f *= float32pow10[exp-10] + exp = 10 + } + if f > 1e7 || f < -1e7 { + // the exponent was really too large. + return + } + return f * float32pow10[exp], true + case exp < 0 && exp >= -10: // int / 10^k + return f / float32pow10[-exp], true + } + return +} + +// atofHex converts the hex floating-point string s +// to a rounded float32 or float64 value (depending on flt==&float32info or flt==&float64info) +// and returns it as a float64. +// The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative). +// If trunc is true, trailing non-zero bits have been omitted from the mantissa. +func atofHex(s string, flt *floatInfo, mantissa uint64, exp int, neg, trunc bool) (float64, error) { + maxExp := 1<>(flt.mantbits+2) == 0 { + mantissa <<= 1 + exp-- + } + if trunc { + mantissa |= 1 + } + for mantissa>>(1+flt.mantbits+2) != 0 { + mantissa = mantissa>>1 | mantissa&1 + exp++ + } + + // If exponent is too negative, + // denormalize in hopes of making it representable. + // (The -2 is for the rounding bits.) + for mantissa > 1 && exp < minExp-2 { + mantissa = mantissa>>1 | mantissa&1 + exp++ + } + + // Round using two bottom bits. + round := mantissa & 3 + mantissa >>= 2 + round |= mantissa & 1 // round to even (round up if mantissa is odd) + exp += 2 + if round == 3 { + mantissa++ + if mantissa == 1<<(1+flt.mantbits) { + mantissa >>= 1 + exp++ + } + } + + if mantissa>>flt.mantbits == 0 { // Denormal or zero. + exp = flt.bias + } + var err error + if exp > maxExp { // infinity and range error + mantissa = 1 << flt.mantbits + exp = maxExp + 1 + err = rangeError(fnParseFloat, s) + } + + bits := mantissa & (1<", "(", ")", "i", "init"} { + in := test.in + suffix + _, n, err := ParseFloatPrefix(in, 64) + if err != nil { + t.Errorf("ParseFloatPrefix(%q, 64): err = %v; want no error", in, err) + } + if n != len(test.in) { + t.Errorf("ParseFloatPrefix(%q, 64): n = %d; want %d", in, n, len(test.in)) + } + } + } +} + +func errEqual(e1, e2 error) bool { + // XXX: used in place of reflect.DeepEqual + if e1 == nil || e2 == nil { + return e1 == e2 + } + return e1.Error() == e2.Error() +} + +func printError(err error) string { + // XXX: gonative fns (like fmt.Printf, t.Errorf...) do not support printing errors + // and it would be very complicated to add. hence we're simplifying them to strings here. + if err == nil { + return "" + } + return err.Error() +} + +func testAtof(t *testing.T, opt bool) { + initAtof() + oldopt := SetOptimize(opt) + for i := 0; i < len(atoftests); i++ { + test := &atoftests[i] + out, err := ParseFloat(test.in, 64) + outs := FormatFloat(out, 'g', -1, 64) + if outs != test.out || !errEqual(err, test.err) { + t.Errorf("ParseFloat(%v, 64) = %v, %v want %v, %v", + test.in, out, printError(err), test.out, printError(test.err)) + } + + if float64(float32(out)) == out { + out, err := ParseFloat(test.in, 32) + out32 := float32(out) + if float64(out32) != out { + t.Errorf("ParseFloat(%v, 32) = %v, not a float32 (closest is %v)", test.in, out, float64(out32)) + continue + } + outs := FormatFloat(float64(out32), 'g', -1, 32) + if outs != test.out || !errEqual(err, test.err) { + t.Errorf("ParseFloat(%v, 32) = %v, %v want %v, %v # %v", + test.in, out32, printError(err), test.out, printError(test.err), out) + } + } + } + for _, test := range atof32tests { + out, err := ParseFloat(test.in, 32) + out32 := float32(out) + if float64(out32) != out { + t.Errorf("ParseFloat(%v, 32) = %v, not a float32 (closest is %v)", test.in, out, float64(out32)) + continue + } + outs := FormatFloat(float64(out32), 'g', -1, 32) + if outs != test.out || !errEqual(err, test.err) { + t.Errorf("ParseFloat(%v, 32) = %v, %v want %v, %v # %v", + test.in, out32, printError(err), test.out, printError(test.err), out) + } + } + SetOptimize(oldopt) +} + +func TestAtof(t *testing.T) { testAtof(t, true) } + +func TestAtofSlow(t *testing.T) { testAtof(t, false) } + +func TestAtofRandom(t *testing.T) { + initAtof() + for _, test := range atofRandomTests { + x, _ := ParseFloat(test.s, 64) + switch { + default: + t.Errorf("number %s badly parsed as %b (expected %b)", test.s, x, test.x) + case x == test.x: + case math.IsNaN(test.x) && math.IsNaN(x): + } + } + t.Logf("tested %d random numbers", len(atofRandomTests)) +} + +var roundTripCases = []struct { + f float64 + s string +}{ + // Issue 2917. + // This test will break the optimized conversion if the + // FPU is using 80-bit registers instead of 64-bit registers, + // usually because the operating system initialized the + // thread with 80-bit precision and the Go runtime didn't + // fix the FP control word. + {8865794286000691 << 39, "4.87402195346389e+27"}, + {8865794286000692 << 39, "4.8740219534638903e+27"}, +} + +func TestRoundTrip(t *testing.T) { + for _, tt := range roundTripCases { + old := SetOptimize(false) + s := FormatFloat(tt.f, 'g', -1, 64) + if s != tt.s { + t.Errorf("no-opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s) + } + f, err := ParseFloat(tt.s, 64) + if f != tt.f || err != nil { + t.Errorf("no-opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f) + } + SetOptimize(true) + s = FormatFloat(tt.f, 'g', -1, 64) + if s != tt.s { + t.Errorf("opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s) + } + f, err = ParseFloat(tt.s, 64) + if f != tt.f || err != nil { + t.Errorf("opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f) + } + SetOptimize(old) + } +} + +// TestRoundTrip32 tries a fraction of all finite positive float32 values. +func TestRoundTrip32(t *testing.T) { + step := uint32(997) + if testing.Short() { + step = 99991 + } + count := 0 + for i := uint32(0); i < 0xff<<23; i += step { + f := math.Float32frombits(i) + if i&1 == 1 { + f = -f // negative + } + s := FormatFloat(float64(f), 'g', -1, 32) + + parsed, err := ParseFloat(s, 32) + parsed32 := float32(parsed) + switch { + case err != nil: + t.Errorf("ParseFloat(%q, 32) gave error %s", s, err) + case float64(parsed32) != parsed: + t.Errorf("ParseFloat(%q, 32) = %v, not a float32 (nearest is %v)", s, parsed, parsed32) + case parsed32 != f: + t.Errorf("ParseFloat(%q, 32) = %b (expected %b)", s, parsed32, f) + } + count++ + } + t.Logf("tested %d float32's", count) +} + +// Issue 42297: a lot of code in the wild accidentally calls ParseFloat(s, 10) +// or ParseFloat(s, 0), so allow bitSize values other than 32 and 64. +func TestParseFloatIncorrectBitSize(t *testing.T) { + const s = "1.5e308" + const want = 1.5e308 + + for _, bitSize := range []int{0, 10, 100, 128} { + f, err := ParseFloat(s, bitSize) + if err != nil { + t.Fatalf("ParseFloat(%q, %d) gave error %s", s, bitSize, err) + } + if f != want { + t.Fatalf("ParseFloat(%q, %d) = %g (expected %g)", s, bitSize, f, want) + } + } +} + +func BenchmarkAtof64Decimal(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("33909", 64) + } +} + +func BenchmarkAtof64Float(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("339.7784", 64) + } +} + +func BenchmarkAtof64FloatExp(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("-5.09e75", 64) + } +} + +func BenchmarkAtof64Big(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("123456789123456789123456789", 64) + } +} + +func BenchmarkAtof64RandomBits(b *testing.B) { + initAtof() + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(benchmarksRandomBits[i%1024], 64) + } +} + +func BenchmarkAtof64RandomFloats(b *testing.B) { + initAtof() + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(benchmarksRandomNormal[i%1024], 64) + } +} + +func BenchmarkAtof64RandomLongFloats(b *testing.B) { + initAtof() + samples := make([]string, len(atofRandomTests)) + for i, t := range atofRandomTests { + samples[i] = FormatFloat(t.x, 'g', 20, 64) + } + b.ResetTimer() + idx := 0 + for i := 0; i < b.N; i++ { + ParseFloat(samples[idx], 64) + idx++ + if idx == len(samples) { + idx = 0 + } + } +} + +func BenchmarkAtof32Decimal(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("33909", 32) + } +} + +func BenchmarkAtof32Float(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("339.778", 32) + } +} + +func BenchmarkAtof32FloatExp(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("12.3456e32", 32) + } +} + +func BenchmarkAtof32Random(b *testing.B) { + n := uint32(997) + var float32strings [4096]string + for i := range float32strings { + n = (99991*n + 42) % (0xff << 23) + float32strings[i] = FormatFloat(float64(math.Float32frombits(n)), 'g', -1, 32) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(float32strings[i%4096], 32) + } +} + +func BenchmarkAtof32RandomLong(b *testing.B) { + n := uint32(997) + var float32strings [4096]string + for i := range float32strings { + n = (99991*n + 42) % (0xff << 23) + float32strings[i] = FormatFloat(float64(math.Float32frombits(n)), 'g', 20, 32) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(float32strings[i%4096], 32) + } +} diff --git a/gnovm/stdlibs/strconv/atoi.gno b/gnovm/stdlibs/strconv/atoi.gno new file mode 100644 index 00000000000..28b8e7f0b14 --- /dev/null +++ b/gnovm/stdlibs/strconv/atoi.gno @@ -0,0 +1,332 @@ +// 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 strconv + +import "errors" + +// lower(c) is a lower-case letter if and only if +// c is either that lower-case letter or the equivalent upper-case letter. +// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. +// Note that lower of non-letters can produce other non-letters. +func lower(c byte) byte { + return c | ('x' - 'X') +} + +// ErrRange indicates that a value is out of range for the target type. +var ErrRange = errors.New("value out of range") + +// ErrSyntax indicates that a value does not have the right syntax for the target type. +var ErrSyntax = errors.New("invalid syntax") + +// A NumError records a failed conversion. +type NumError struct { + Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) + Num string // the input + Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.) +} + +func (e *NumError) Error() string { + return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error() +} + +func (e *NumError) Unwrap() error { return e.Err } + +// cloneString returns a string copy of x. +// +// All ParseXXX functions allow the input string to escape to the error value. +// This hurts strconv.ParseXXX(string(b)) calls where b is []byte since +// the conversion from []byte must allocate a string on the heap. +// If we assume errors are infrequent, then we can avoid escaping the input +// back to the output by copying it first. This allows the compiler to call +// strconv.ParseXXX without a heap allocation for most []byte to string +// conversions, since it can now prove that the string cannot escape Parse. +// +// TODO: Use strings.Clone instead? However, we cannot depend on "strings" +// since it incurs a transitive dependency on "unicode". +// Either move strings.Clone to an internal/bytealg or make the +// "strings" to "unicode" dependency lighter (see https://go.dev/issue/54098). +func cloneString(x string) string { return string([]byte(x)) } + +func syntaxError(fn, str string) *NumError { + return &NumError{fn, cloneString(str), ErrSyntax} +} + +func rangeError(fn, str string) *NumError { + return &NumError{fn, cloneString(str), ErrRange} +} + +func baseError(fn, str string, base int) *NumError { + return &NumError{fn, cloneString(str), errors.New("invalid base " + Itoa(base))} +} + +func bitSizeError(fn, str string, bitSize int) *NumError { + return &NumError{fn, cloneString(str), errors.New("invalid bit size " + Itoa(bitSize))} +} + +const intSize = 32 << (^uint(0) >> 63) + +// IntSize is the size in bits of an int or uint value. +const IntSize = intSize + +const maxUint64 = 1<<64 - 1 + +// ParseUint is like ParseInt but for unsigned numbers. +// +// A sign prefix is not permitted. +func ParseUint(s string, base int, bitSize int) (uint64, error) { + const fnParseUint = "ParseUint" + + if s == "" { + return 0, syntaxError(fnParseUint, s) + } + + base0 := base == 0 + + s0 := s + switch { + case 2 <= base && base <= 36: + // valid base; nothing to do + + case base == 0: + // Look for octal, hex prefix. + base = 10 + if s[0] == '0' { + switch { + case len(s) >= 3 && lower(s[1]) == 'b': + base = 2 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'o': + base = 8 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'x': + base = 16 + s = s[2:] + default: + base = 8 + s = s[1:] + } + } + + default: + return 0, baseError(fnParseUint, s0, base) + } + + if bitSize == 0 { + bitSize = IntSize + } else if bitSize < 0 || bitSize > 64 { + return 0, bitSizeError(fnParseUint, s0, bitSize) + } + + // Cutoff is the smallest number such that cutoff*base > maxUint64. + // Use compile-time constants for common cases. + var cutoff uint64 + switch base { + case 10: + cutoff = maxUint64/10 + 1 + case 16: + cutoff = maxUint64/16 + 1 + default: + cutoff = maxUint64/uint64(base) + 1 + } + + maxVal := uint64(1)<= byte(base) { + return 0, syntaxError(fnParseUint, s0) + } + + if n >= cutoff { + // n*base overflows + return maxVal, rangeError(fnParseUint, s0) + } + n *= uint64(base) + + n1 := n + uint64(d) + if n1 < n || n1 > maxVal { + // n+d overflows + return maxVal, rangeError(fnParseUint, s0) + } + n = n1 + } + + if underscores && !underscoreOK(s0) { + return 0, syntaxError(fnParseUint, s0) + } + + return n, nil +} + +// ParseInt interprets a string s in the given base (0, 2 to 36) and +// bit size (0 to 64) and returns the corresponding value i. +// +// The string may begin with a leading sign: "+" or "-". +// +// If the base argument is 0, the true base is implied by the string's +// prefix following the sign (if present): 2 for "0b", 8 for "0" or "0o", +// 16 for "0x", and 10 otherwise. Also, for argument base 0 only, +// underscore characters are permitted as defined by the Go syntax for +// [integer literals]. +// +// The bitSize argument specifies the integer type +// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 +// correspond to int, int8, int16, int32, and int64. +// If bitSize is below 0 or above 64, an error is returned. +// +// The errors that ParseInt returns have concrete type *NumError +// and include err.Num = s. If s is empty or contains invalid +// digits, err.Err = ErrSyntax and the returned value is 0; +// if the value corresponding to s cannot be represented by a +// signed integer of the given size, err.Err = ErrRange and the +// returned value is the maximum magnitude integer of the +// appropriate bitSize and sign. +// +// [integer literals]: https://go.dev/ref/spec#Integer_literals +func ParseInt(s string, base int, bitSize int) (i int64, err error) { + const fnParseInt = "ParseInt" + + if s == "" { + return 0, syntaxError(fnParseInt, s) + } + + // Pick off leading sign. + s0 := s + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + neg = true + s = s[1:] + } + + // Convert unsigned and check range. + var un uint64 + un, err = ParseUint(s, base, bitSize) + if err != nil && err.(*NumError).Err != ErrRange { + err.(*NumError).Func = fnParseInt + err.(*NumError).Num = cloneString(s0) + return 0, err + } + + if bitSize == 0 { + bitSize = IntSize + } + + cutoff := uint64(1 << uint(bitSize-1)) + if !neg && un >= cutoff { + return int64(cutoff - 1), rangeError(fnParseInt, s0) + } + if neg && un > cutoff { + return -int64(cutoff), rangeError(fnParseInt, s0) + } + n := int64(un) + if neg { + n = -n + } + return n, nil +} + +// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int. +func Atoi(s string) (int, error) { + const fnAtoi = "Atoi" + + sLen := len(s) + if intSize == 32 && (0 < sLen && sLen < 10) || + intSize == 64 && (0 < sLen && sLen < 19) { + // Fast path for small integers that fit int type. + s0 := s + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) < 1 { + return 0, syntaxError(fnAtoi, s0) + } + } + + n := 0 + for _, ch := range []byte(s) { + ch -= '0' + if ch > 9 { + return 0, syntaxError(fnAtoi, s0) + } + n = n*10 + int(ch) + } + if s0[0] == '-' { + n = -n + } + return n, nil + } + + // Slow path for invalid, big, or underscored integers. + i64, err := ParseInt(s, 10, 0) + if nerr, ok := err.(*NumError); ok { + nerr.Func = fnAtoi + } + return int(i64), err +} + +// underscoreOK reports whether the underscores in s are allowed. +// Checking them in this one function lets all the parsers skip over them simply. +// Underscore must appear only between digits or between a base prefix and a digit. +func underscoreOK(s string) bool { + // saw tracks the last character (class) we saw: + // ^ for beginning of number, + // 0 for a digit or base prefix, + // _ for an underscore, + // ! for none of the above. + saw := '^' + i := 0 + + // Optional sign. + if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { + s = s[1:] + } + + // Optional base prefix. + hex := false + if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { + i = 2 + saw = '0' // base prefix counts as a digit for "underscore as digit separator" + hex = lower(s[1]) == 'x' + } + + // Number proper. + for ; i < len(s); i++ { + // Digits are always okay. + if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { + saw = '0' + continue + } + // Underscore must follow digit. + if s[i] == '_' { + if saw != '0' { + return false + } + saw = '_' + continue + } + // Underscore must also be followed by digit. + if saw == '_' { + return false + } + // Saw non-digit, non-underscore. + saw = '!' + } + return saw != '_' +} diff --git a/gnovm/stdlibs/strconv/atoi_test.gno b/gnovm/stdlibs/strconv/atoi_test.gno new file mode 100644 index 00000000000..cb150628f5c --- /dev/null +++ b/gnovm/stdlibs/strconv/atoi_test.gno @@ -0,0 +1,677 @@ +// 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 strconv + +import ( + "errors" + "fmt" + "testing" +) + +type parseUint64Test struct { + in string + out uint64 + err error +} + +var parseUint64Tests = []parseUint64Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 12345, nil}, + {"12345x", 0, ErrSyntax}, + {"98765432100", 98765432100, nil}, + {"18446744073709551615", 1<<64 - 1, nil}, + {"18446744073709551616", 1<<64 - 1, ErrRange}, + {"18446744073709551620", 1<<64 - 1, ErrRange}, + {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, + {"-0", 0, ErrSyntax}, + {"-1", 0, ErrSyntax}, + {"+1", 0, ErrSyntax}, +} + +type parseUint64BaseTest struct { + in string + base int + out uint64 + err error +} + +var parseUint64BaseTests = []parseUint64BaseTest{ + {"", 0, 0, ErrSyntax}, + {"0", 0, 0, nil}, + {"0x", 0, 0, ErrSyntax}, + {"0X", 0, 0, ErrSyntax}, + {"1", 0, 1, nil}, + {"12345", 0, 12345, nil}, + {"012345", 0, 012345, nil}, + {"0x12345", 0, 0x12345, nil}, + {"0X12345", 0, 0x12345, nil}, + {"12345x", 0, 0, ErrSyntax}, + {"0xabcdefg123", 0, 0, ErrSyntax}, + {"123456789abc", 0, 0, ErrSyntax}, + {"98765432100", 0, 98765432100, nil}, + {"18446744073709551615", 0, 1<<64 - 1, nil}, + {"18446744073709551616", 0, 1<<64 - 1, ErrRange}, + {"18446744073709551620", 0, 1<<64 - 1, ErrRange}, + {"0xFFFFFFFFFFFFFFFF", 0, 1<<64 - 1, nil}, + {"0x10000000000000000", 0, 1<<64 - 1, ErrRange}, + {"01777777777777777777777", 0, 1<<64 - 1, nil}, + {"01777777777777777777778", 0, 0, ErrSyntax}, + {"02000000000000000000000", 0, 1<<64 - 1, ErrRange}, + {"0200000000000000000000", 0, 1 << 61, nil}, + {"0b", 0, 0, ErrSyntax}, + {"0B", 0, 0, ErrSyntax}, + {"0b101", 0, 5, nil}, + {"0B101", 0, 5, nil}, + {"0o", 0, 0, ErrSyntax}, + {"0O", 0, 0, ErrSyntax}, + {"0o377", 0, 255, nil}, + {"0O377", 0, 255, nil}, + + // underscores allowed with base == 0 only + {"1_2_3_4_5", 0, 12345, nil}, // base 0 => 10 + {"_12345", 0, 0, ErrSyntax}, + {"1__2345", 0, 0, ErrSyntax}, + {"12345_", 0, 0, ErrSyntax}, + + {"1_2_3_4_5", 10, 0, ErrSyntax}, // base 10 + {"_12345", 10, 0, ErrSyntax}, + {"1__2345", 10, 0, ErrSyntax}, + {"12345_", 10, 0, ErrSyntax}, + + {"0x_1_2_3_4_5", 0, 0x12345, nil}, // base 0 => 16 + {"_0x12345", 0, 0, ErrSyntax}, + {"0x__12345", 0, 0, ErrSyntax}, + {"0x1__2345", 0, 0, ErrSyntax}, + {"0x1234__5", 0, 0, ErrSyntax}, + {"0x12345_", 0, 0, ErrSyntax}, + + {"1_2_3_4_5", 16, 0, ErrSyntax}, // base 16 + {"_12345", 16, 0, ErrSyntax}, + {"1__2345", 16, 0, ErrSyntax}, + {"1234__5", 16, 0, ErrSyntax}, + {"12345_", 16, 0, ErrSyntax}, + + {"0_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0377) + {"_012345", 0, 0, ErrSyntax}, + {"0__12345", 0, 0, ErrSyntax}, + {"01234__5", 0, 0, ErrSyntax}, + {"012345_", 0, 0, ErrSyntax}, + + {"0o_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0o377) + {"_0o12345", 0, 0, ErrSyntax}, + {"0o__12345", 0, 0, ErrSyntax}, + {"0o1234__5", 0, 0, ErrSyntax}, + {"0o12345_", 0, 0, ErrSyntax}, + + {"0_1_2_3_4_5", 8, 0, ErrSyntax}, // base 8 + {"_012345", 8, 0, ErrSyntax}, + {"0__12345", 8, 0, ErrSyntax}, + {"01234__5", 8, 0, ErrSyntax}, + {"012345_", 8, 0, ErrSyntax}, + + {"0b_1_0_1", 0, 5, nil}, // base 0 => 2 (0b101) + {"_0b101", 0, 0, ErrSyntax}, + {"0b__101", 0, 0, ErrSyntax}, + {"0b1__01", 0, 0, ErrSyntax}, + {"0b10__1", 0, 0, ErrSyntax}, + {"0b101_", 0, 0, ErrSyntax}, + + {"1_0_1", 2, 0, ErrSyntax}, // base 2 + {"_101", 2, 0, ErrSyntax}, + {"1_01", 2, 0, ErrSyntax}, + {"10_1", 2, 0, ErrSyntax}, + {"101_", 2, 0, ErrSyntax}, +} + +type parseInt64Test struct { + in string + out int64 + err error +} + +var parseInt64Tests = []parseInt64Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"+0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"+1", 1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 12345, nil}, + {"-012345", -12345, nil}, + {"98765432100", 98765432100, nil}, + {"-98765432100", -98765432100, nil}, + {"9223372036854775807", 1<<63 - 1, nil}, + {"-9223372036854775807", -(1<<63 - 1), nil}, + {"9223372036854775808", 1<<63 - 1, ErrRange}, + {"-9223372036854775808", -1 << 63, nil}, + {"9223372036854775809", 1<<63 - 1, ErrRange}, + {"-9223372036854775809", -1 << 63, ErrRange}, + {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"-_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, + {"123%45", 0, ErrSyntax}, +} + +type parseInt64BaseTest struct { + in string + base int + out int64 + err error +} + +var parseInt64BaseTests = []parseInt64BaseTest{ + {"", 0, 0, ErrSyntax}, + {"0", 0, 0, nil}, + {"-0", 0, 0, nil}, + {"1", 0, 1, nil}, + {"-1", 0, -1, nil}, + {"12345", 0, 12345, nil}, + {"-12345", 0, -12345, nil}, + {"012345", 0, 012345, nil}, + {"-012345", 0, -012345, nil}, + {"0x12345", 0, 0x12345, nil}, + {"-0X12345", 0, -0x12345, nil}, + {"12345x", 0, 0, ErrSyntax}, + {"-12345x", 0, 0, ErrSyntax}, + {"98765432100", 0, 98765432100, nil}, + {"-98765432100", 0, -98765432100, nil}, + {"9223372036854775807", 0, 1<<63 - 1, nil}, + {"-9223372036854775807", 0, -(1<<63 - 1), nil}, + {"9223372036854775808", 0, 1<<63 - 1, ErrRange}, + {"-9223372036854775808", 0, -1 << 63, nil}, + {"9223372036854775809", 0, 1<<63 - 1, ErrRange}, + {"-9223372036854775809", 0, -1 << 63, ErrRange}, + + // other bases + {"g", 17, 16, nil}, + {"10", 25, 25, nil}, + {"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil}, + {"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil}, + + // base 2 + {"0", 2, 0, nil}, + {"-1", 2, -1, nil}, + {"1010", 2, 10, nil}, + {"1000000000000000", 2, 1 << 15, nil}, + {"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil}, + {"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange}, + {"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil}, + {"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange}, + + // base 8 + {"-10", 8, -8, nil}, + {"57635436545", 8, 057635436545, nil}, + {"100000000", 8, 1 << 24, nil}, + + // base 16 + {"10", 16, 16, nil}, + {"-123456789abcdef", 16, -0x123456789abcdef, nil}, + {"7fffffffffffffff", 16, 1<<63 - 1, nil}, + + // underscores + {"-0x_1_2_3_4_5", 0, -0x12345, nil}, + {"0x_1_2_3_4_5", 0, 0x12345, nil}, + {"-_0x12345", 0, 0, ErrSyntax}, + {"_-0x12345", 0, 0, ErrSyntax}, + {"_0x12345", 0, 0, ErrSyntax}, + {"0x__12345", 0, 0, ErrSyntax}, + {"0x1__2345", 0, 0, ErrSyntax}, + {"0x1234__5", 0, 0, ErrSyntax}, + {"0x12345_", 0, 0, ErrSyntax}, + + {"-0_1_2_3_4_5", 0, -012345, nil}, // octal + {"0_1_2_3_4_5", 0, 012345, nil}, // octal + {"-_012345", 0, 0, ErrSyntax}, + {"_-012345", 0, 0, ErrSyntax}, + {"_012345", 0, 0, ErrSyntax}, + {"0__12345", 0, 0, ErrSyntax}, + {"01234__5", 0, 0, ErrSyntax}, + {"012345_", 0, 0, ErrSyntax}, + + {"+0xf", 0, 0xf, nil}, + {"-0xf", 0, -0xf, nil}, + {"0x+f", 0, 0, ErrSyntax}, + {"0x-f", 0, 0, ErrSyntax}, +} + +type parseUint32Test struct { + in string + out uint32 + err error +} + +var parseUint32Tests = []parseUint32Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 12345, nil}, + {"12345x", 0, ErrSyntax}, + {"987654321", 987654321, nil}, + {"4294967295", 1<<32 - 1, nil}, + {"4294967296", 1<<32 - 1, ErrRange}, + {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, +} + +type parseInt32Test struct { + in string + out int32 + err error +} + +var parseInt32Tests = []parseInt32Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 12345, nil}, + {"-012345", -12345, nil}, + {"12345x", 0, ErrSyntax}, + {"-12345x", 0, ErrSyntax}, + {"987654321", 987654321, nil}, + {"-987654321", -987654321, nil}, + {"2147483647", 1<<31 - 1, nil}, + {"-2147483647", -(1<<31 - 1), nil}, + {"2147483648", 1<<31 - 1, ErrRange}, + {"-2147483648", -1 << 31, nil}, + {"2147483649", 1<<31 - 1, ErrRange}, + {"-2147483649", -1 << 31, ErrRange}, + {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"-_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, + {"123%45", 0, ErrSyntax}, +} + +type numErrorTest struct { + num, want string +} + +var numErrorTests = []numErrorTest{ + {"0", `strconv.ParseFloat: parsing "0": failed`}, + {"`", "strconv.ParseFloat: parsing \"`\": failed"}, + {"1\x00.2", `strconv.ParseFloat: parsing "1\x00.2": failed`}, +} + +func init() { + // The parse routines return NumErrors wrapping + // the error and the string. Convert the tables above. + for i := range parseUint64Tests { + test := &parseUint64Tests[i] + if test.err != nil { + test.err = &NumError{"ParseUint", test.in, test.err} + } + } + for i := range parseUint64BaseTests { + test := &parseUint64BaseTests[i] + if test.err != nil { + test.err = &NumError{"ParseUint", test.in, test.err} + } + } + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + if test.err != nil { + test.err = &NumError{"ParseInt", test.in, test.err} + } + } + for i := range parseInt64BaseTests { + test := &parseInt64BaseTests[i] + if test.err != nil { + test.err = &NumError{"ParseInt", test.in, test.err} + } + } + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + if test.err != nil { + test.err = &NumError{"ParseUint", test.in, test.err} + } + } + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + if test.err != nil { + test.err = &NumError{"ParseInt", test.in, test.err} + } + } +} + +func TestParseUint32(t *testing.T) { + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + out, err := ParseUint(test.in, 10, 32) + if uint64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 32) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseUint64(t *testing.T) { + for i := range parseUint64Tests { + test := &parseUint64Tests[i] + out, err := ParseUint(test.in, 10, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 64) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseUint64Base(t *testing.T) { + for i := range parseUint64BaseTests { + test := &parseUint64BaseTests[i] + out, err := ParseUint(test.in, test.base, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, %v, 64) = %v, %v want %v, %v", + test.in, test.base, out, err, test.out, test.err) + } + } +} + +func TestParseInt32(t *testing.T) { + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := ParseInt(test.in, 10, 32) + if int64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10 ,32) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseInt64(t *testing.T) { + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := ParseInt(test.in, 10, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 64) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseInt64Base(t *testing.T) { + for i := range parseInt64BaseTests { + test := &parseInt64BaseTests[i] + out, err := ParseInt(test.in, test.base, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, %v, 64) = %v, %v want %v, %v", + test.in, test.base, out, err, test.out, test.err) + } + } +} + +func TestParseUint(t *testing.T) { + switch IntSize { + case 32: + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + out, err := ParseUint(test.in, 10, 0) + if uint64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + case 64: + for i := range parseUint64Tests { + test := &parseUint64Tests[i] + out, err := ParseUint(test.in, 10, 0) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + } +} + +func TestParseInt(t *testing.T) { + switch IntSize { + case 32: + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := ParseInt(test.in, 10, 0) + if int64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + case 64: + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := ParseInt(test.in, 10, 0) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + } +} + +func TestAtoi(t *testing.T) { + switch IntSize { + case 32: + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := Atoi(test.in) + var testErr error + if test.err != nil { + testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err} + } + if int(test.out) != out || !errEqual(testErr, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, testErr) + } + } + case 64: + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := Atoi(test.in) + var testErr error + if test.err != nil { + testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err} + } + if test.out != int64(out) || !errEqual(testErr, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, testErr) + } + } + } +} + +func bitSizeErrStub(name string, bitSize int) error { + return BitSizeError(name, "0", bitSize) +} + +func baseErrStub(name string, base int) error { + return BaseError(name, "0", base) +} + +func noErrStub(name string, arg int) error { + return nil +} + +type parseErrorTest struct { + arg int + errStub func(name string, arg int) error +} + +var parseBitSizeTests = []parseErrorTest{ + {-1, bitSizeErrStub}, + {0, noErrStub}, + {64, noErrStub}, + {65, bitSizeErrStub}, +} + +var parseBaseTests = []parseErrorTest{ + {-1, baseErrStub}, + {0, noErrStub}, + {1, baseErrStub}, + {2, noErrStub}, + {36, noErrStub}, + {37, baseErrStub}, +} + +func equalError(a, b error) bool { + if a == nil { + return b == nil + } + if b == nil { + return a == nil + } + return a.Error() == b.Error() +} + +func TestParseIntBitSize(t *testing.T) { + for i := range parseBitSizeTests { + test := &parseBitSizeTests[i] + testErr := test.errStub("ParseInt", test.arg) + _, err := ParseInt("0", 0, test.arg) + if !equalError(testErr, err) { + t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseUintBitSize(t *testing.T) { + for i := range parseBitSizeTests { + test := &parseBitSizeTests[i] + testErr := test.errStub("ParseUint", test.arg) + _, err := ParseUint("0", 0, test.arg) + if !equalError(testErr, err) { + t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseIntBase(t *testing.T) { + for i := range parseBaseTests { + test := &parseBaseTests[i] + testErr := test.errStub("ParseInt", test.arg) + _, err := ParseInt("0", test.arg, 0) + if !equalError(testErr, err) { + t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseUintBase(t *testing.T) { + for i := range parseBaseTests { + test := &parseBaseTests[i] + testErr := test.errStub("ParseUint", test.arg) + _, err := ParseUint("0", test.arg, 0) + if !equalError(testErr, err) { + t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestNumError(t *testing.T) { + for _, test := range numErrorTests { + err := &NumError{ + Func: "ParseFloat", + Num: test.num, + Err: errors.New("failed"), + } + if got := err.Error(); got != test.want { + t.Errorf(`(&NumError{"ParseFloat", %q, "failed"}).Error() = %v, want %v`, test.num, got, test.want) + } + } +} + +/* XXX: add when we support reflection / error un/wrapping. +func TestNumErrorUnwrap(t *testing.T) { + err := &NumError{Err: ErrSyntax} + if !errEqual(err, ErrSyntax) { + t.Error("errors.Is failed, wanted success") + } +} +*/ + +func BenchmarkParseInt(b *testing.B) { + b.Run("Pos", func(b *testing.B) { + benchmarkParseInt(b, 1) + }) + b.Run("Neg", func(b *testing.B) { + benchmarkParseInt(b, -1) + }) +} + +type benchCase struct { + name string + num int64 +} + +func benchmarkParseInt(b *testing.B, neg int) { + cases := []benchCase{ + {"7bit", 1<<7 - 1}, + {"26bit", 1<<26 - 1}, + {"31bit", 1<<31 - 1}, + {"56bit", 1<<56 - 1}, + {"63bit", 1<<63 - 1}, + } + for _, cs := range cases { + b.Run(cs.name, func(b *testing.B) { + s := fmt.Sprintf("%d", cs.num*int64(neg)) + for i := 0; i < b.N; i++ { + out, _ := ParseInt(s, 10, 64) + BenchSink += int(out) + } + }) + } +} + +func BenchmarkAtoi(b *testing.B) { + b.Run("Pos", func(b *testing.B) { + benchmarkAtoi(b, 1) + }) + b.Run("Neg", func(b *testing.B) { + benchmarkAtoi(b, -1) + }) +} + +func benchmarkAtoi(b *testing.B, neg int) { + cases := []benchCase{ + {"7bit", 1<<7 - 1}, + {"26bit", 1<<26 - 1}, + {"31bit", 1<<31 - 1}, + } + if IntSize == 64 { + cases = append(cases, []benchCase{ + {"56bit", 1<<56 - 1}, + {"63bit", 1<<63 - 1}, + }...) + } + for _, cs := range cases { + b.Run(cs.name, func(b *testing.B) { + s := fmt.Sprintf("%d", cs.num*int64(neg)) + for i := 0; i < b.N; i++ { + out, _ := Atoi(s) + BenchSink += out + } + }) + } +} diff --git a/gnovm/stdlibs/strconv/bytealg.gno b/gnovm/stdlibs/strconv/bytealg.gno new file mode 100644 index 00000000000..2c813885f53 --- /dev/null +++ b/gnovm/stdlibs/strconv/bytealg.gno @@ -0,0 +1,12 @@ +// 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 strconv + +import "internal/bytealg" + +// index returns the index of the first instance of c in s, or -1 if missing. +func index(s string, c byte) int { + return bytealg.IndexByteString(s, c) +} diff --git a/gnovm/stdlibs/strconv/decimal.gno b/gnovm/stdlibs/strconv/decimal.gno new file mode 100644 index 00000000000..b58001888e8 --- /dev/null +++ b/gnovm/stdlibs/strconv/decimal.gno @@ -0,0 +1,415 @@ +// 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. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package strconv + +type decimal struct { + d [800]byte // digits, big-endian representation + nd int // number of digits used + dp int // decimal point + neg bool // negative flag + trunc bool // discarded nonzero digits beyond d[:nd] +} + +func (a *decimal) String() string { + n := 10 + a.nd + if a.dp > 0 { + n += a.dp + } + if a.dp < 0 { + n += -a.dp + } + + buf := make([]byte, n) + w := 0 + switch { + case a.nd == 0: + return "0" + + case a.dp <= 0: + // zeros fill space between decimal point and digits + buf[w] = '0' + w++ + buf[w] = '.' + w++ + w += digitZero(buf[w : w+-a.dp]) + w += copy(buf[w:], a.d[0:a.nd]) + + case a.dp < a.nd: + // decimal point in middle of digits + w += copy(buf[w:], a.d[0:a.dp]) + buf[w] = '.' + w++ + w += copy(buf[w:], a.d[a.dp:a.nd]) + + default: + // zeros fill space between digits and decimal point + w += copy(buf[w:], a.d[0:a.nd]) + w += digitZero(buf[w : w+a.dp-a.nd]) + } + return string(buf[0:w]) +} + +func digitZero(dst []byte) int { + for i := range dst { + dst[i] = '0' + } + return len(dst) +} + +// trim trailing zeros from number. +// (They are meaningless; the decimal point is tracked +// independent of the number of digits.) +func trim(a *decimal) { + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd-- + } + if a.nd == 0 { + a.dp = 0 + } +} + +// Assign v to a. +func (a *decimal) Assign(v uint64) { + var buf [24]byte + + // Write reversed decimal in buf. + n := 0 + for v > 0 { + v1 := v / 10 + v -= 10 * v1 + buf[n] = byte(v + '0') + n++ + v = v1 + } + + // Reverse again to produce forward decimal in a.d. + a.nd = 0 + for n--; n >= 0; n-- { + a.d[a.nd] = buf[n] + a.nd++ + } + a.dp = a.nd + trim(a) +} + +// Maximum shift that we can do in one pass without overflow. +// A uint has 32 or 64 bits, and we have to be able to accommodate 9<> 63) +const maxShift = uintSize - 4 + +// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. +func rightShift(a *decimal, k uint) { + r := 0 // read pointer + w := 0 // write pointer + + // Pick up enough leading digits to cover first shift. + var n uint + for ; n>>k == 0; r++ { + if r >= a.nd { + if n == 0 { + // a == 0; shouldn't get here, but handle anyway. + a.nd = 0 + return + } + for n>>k == 0 { + n = n * 10 + r++ + } + break + } + c := uint(a.d[r]) + n = n*10 + c - '0' + } + a.dp -= r - 1 + + var mask uint = (1 << k) - 1 + + // Pick up a digit, put down a digit. + for ; r < a.nd; r++ { + c := uint(a.d[r]) + dig := n >> k + n &= mask + a.d[w] = byte(dig + '0') + w++ + n = n*10 + c - '0' + } + + // Put down extra digits. + for n > 0 { + dig := n >> k + n &= mask + if w < len(a.d) { + a.d[w] = byte(dig + '0') + w++ + } else if dig > 0 { + a.trunc = true + } + n = n * 10 + } + + a.nd = w + trim(a) +} + +// Cheat sheet for left shift: table indexed by shift count giving +// number of new digits that will be introduced by that shift. +// +// For example, leftcheats[4] = {2, "625"}. That means that +// if we are shifting by 4 (multiplying by 16), it will add 2 digits +// when the string prefix is "625" through "999", and one fewer digit +// if the string prefix is "000" through "624". +// +// Credit for this trick goes to Ken. + +type leftCheat struct { + delta int // number of new digits + cutoff string // minus one digit if original < a. +} + +var leftcheats = []leftCheat{ + // Leading digits of 1/2^i = 5^i. + // 5^23 is not an exact 64-bit floating point number, + // so have to use bc for the math. + // Go up to 60 to be large enough for 32bit and 64bit platforms. + /* + seq 60 | sed 's/^/5^/' | bc | + awk 'BEGIN{ print "\t{ 0, \"\" }," } + { + log2 = log(2)/log(10) + printf("\t{ %d, \"%s\" },\t// * %d\n", + int(log2*NR+1), $0, 2**NR) + }' + */ + {0, ""}, + {1, "5"}, // * 2 + {1, "25"}, // * 4 + {1, "125"}, // * 8 + {2, "625"}, // * 16 + {2, "3125"}, // * 32 + {2, "15625"}, // * 64 + {3, "78125"}, // * 128 + {3, "390625"}, // * 256 + {3, "1953125"}, // * 512 + {4, "9765625"}, // * 1024 + {4, "48828125"}, // * 2048 + {4, "244140625"}, // * 4096 + {4, "1220703125"}, // * 8192 + {5, "6103515625"}, // * 16384 + {5, "30517578125"}, // * 32768 + {5, "152587890625"}, // * 65536 + {6, "762939453125"}, // * 131072 + {6, "3814697265625"}, // * 262144 + {6, "19073486328125"}, // * 524288 + {7, "95367431640625"}, // * 1048576 + {7, "476837158203125"}, // * 2097152 + {7, "2384185791015625"}, // * 4194304 + {7, "11920928955078125"}, // * 8388608 + {8, "59604644775390625"}, // * 16777216 + {8, "298023223876953125"}, // * 33554432 + {8, "1490116119384765625"}, // * 67108864 + {9, "7450580596923828125"}, // * 134217728 + {9, "37252902984619140625"}, // * 268435456 + {9, "186264514923095703125"}, // * 536870912 + {10, "931322574615478515625"}, // * 1073741824 + {10, "4656612873077392578125"}, // * 2147483648 + {10, "23283064365386962890625"}, // * 4294967296 + {10, "116415321826934814453125"}, // * 8589934592 + {11, "582076609134674072265625"}, // * 17179869184 + {11, "2910383045673370361328125"}, // * 34359738368 + {11, "14551915228366851806640625"}, // * 68719476736 + {12, "72759576141834259033203125"}, // * 137438953472 + {12, "363797880709171295166015625"}, // * 274877906944 + {12, "1818989403545856475830078125"}, // * 549755813888 + {13, "9094947017729282379150390625"}, // * 1099511627776 + {13, "45474735088646411895751953125"}, // * 2199023255552 + {13, "227373675443232059478759765625"}, // * 4398046511104 + {13, "1136868377216160297393798828125"}, // * 8796093022208 + {14, "5684341886080801486968994140625"}, // * 17592186044416 + {14, "28421709430404007434844970703125"}, // * 35184372088832 + {14, "142108547152020037174224853515625"}, // * 70368744177664 + {15, "710542735760100185871124267578125"}, // * 140737488355328 + {15, "3552713678800500929355621337890625"}, // * 281474976710656 + {15, "17763568394002504646778106689453125"}, // * 562949953421312 + {16, "88817841970012523233890533447265625"}, // * 1125899906842624 + {16, "444089209850062616169452667236328125"}, // * 2251799813685248 + {16, "2220446049250313080847263336181640625"}, // * 4503599627370496 + {16, "11102230246251565404236316680908203125"}, // * 9007199254740992 + {17, "55511151231257827021181583404541015625"}, // * 18014398509481984 + {17, "277555756156289135105907917022705078125"}, // * 36028797018963968 + {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936 + {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872 + {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744 + {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488 + {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976 +} + +// Is the leading prefix of b lexicographically less than s? +func prefixIsLessThan(b []byte, s string) bool { + for i := 0; i < len(s); i++ { + if i >= len(b) { + return true + } + if b[i] != s[i] { + return b[i] < s[i] + } + } + return false +} + +// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. +func leftShift(a *decimal, k uint) { + delta := leftcheats[k].delta + if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { + delta-- + } + + r := a.nd // read index + w := a.nd + delta // write index + + // Pick up a digit, put down a digit. + var n uint + for r--; r >= 0; r-- { + n += (uint(a.d[r]) - '0') << k + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + // Put down extra digits. + for n > 0 { + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + a.nd += delta + if a.nd >= len(a.d) { + a.nd = len(a.d) + } + a.dp += delta + trim(a) +} + +// Binary shift left (k > 0) or right (k < 0). +func (a *decimal) Shift(k int) { + switch { + case a.nd == 0: + // nothing to do: a == 0 + case k > 0: + for k > maxShift { + leftShift(a, maxShift) + k -= maxShift + } + leftShift(a, uint(k)) + case k < 0: + for k < -maxShift { + rightShift(a, maxShift) + k += maxShift + } + rightShift(a, uint(-k)) + } +} + +// If we chop a at nd digits, should we round up? +func shouldRoundUp(a *decimal, nd int) bool { + if nd < 0 || nd >= a.nd { + return false + } + if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + // if we truncated, a little higher than what's recorded - always round up + if a.trunc { + return true + } + return nd > 0 && (a.d[nd-1]-'0')%2 != 0 + } + // not halfway - digit tells all + return a.d[nd] >= '5' +} + +// Round a to nd digits (or fewer). +// If nd is zero, it means we're rounding +// just to the left of the digits, as in +// 0.09 -> 0.1. +func (a *decimal) Round(nd int) { + if nd < 0 || nd >= a.nd { + return + } + if shouldRoundUp(a, nd) { + a.RoundUp(nd) + } else { + a.RoundDown(nd) + } +} + +// Round a down to nd digits (or fewer). +func (a *decimal) RoundDown(nd int) { + if nd < 0 || nd >= a.nd { + return + } + a.nd = nd + trim(a) +} + +// Round a up to nd digits (or fewer). +func (a *decimal) RoundUp(nd int) { + if nd < 0 || nd >= a.nd { + return + } + + // round up + for i := nd - 1; i >= 0; i-- { + c := a.d[i] + if c < '9' { // can stop after this digit + a.d[i]++ + a.nd = i + 1 + return + } + } + + // Number is all 9s. + // Change to single 1 with adjusted decimal point. + a.d[0] = '1' + a.nd = 1 + a.dp++ +} + +// Extract integer part, rounded appropriately. +// No guarantees about overflow. +func (a *decimal) RoundedInteger() uint64 { + if a.dp > 20 { + return 0xFFFFFFFFFFFFFFFF + } + var i int + n := uint64(0) + for i = 0; i < a.dp && i < a.nd; i++ { + n = n*10 + uint64(a.d[i]-'0') + } + for ; i < a.dp; i++ { + n *= 10 + } + if shouldRoundUp(a, a.dp) { + n++ + } + return n +} diff --git a/gnovm/stdlibs/strconv/decimal_test.gno b/gnovm/stdlibs/strconv/decimal_test.gno new file mode 100644 index 00000000000..9dc8c997b9c --- /dev/null +++ b/gnovm/stdlibs/strconv/decimal_test.gno @@ -0,0 +1,126 @@ +// 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 strconv + +import ( + "testing" +) + +type shiftTest struct { + i uint64 + shift int + out string +} + +var shifttests = []shiftTest{ + {0, -100, "0"}, + {0, 100, "0"}, + {1, 100, "1267650600228229401496703205376"}, + {1, -100, + "0.00000000000000000000000000000078886090522101180541" + + "17285652827862296732064351090230047702789306640625", + }, + {12345678, 8, "3160493568"}, + {12345678, -8, "48225.3046875"}, + {195312, 9, "99999744"}, + {1953125, 9, "1000000000"}, +} + +func TestDecimalShift(t *testing.T) { + for i := 0; i < len(shifttests); i++ { + test := &shifttests[i] + d := NewDecimal(test.i) + d.Shift(test.shift) + s := d.String() + if s != test.out { + t.Errorf("Decimal %v << %v = %v, want %v", + test.i, test.shift, s, test.out) + } + } +} + +type roundTest struct { + i uint64 + nd int + down, round, up string + int uint64 +} + +var roundtests = []roundTest{ + {0, 4, "0", "0", "0", 0}, + {12344999, 4, "12340000", "12340000", "12350000", 12340000}, + {12345000, 4, "12340000", "12340000", "12350000", 12340000}, + {12345001, 4, "12340000", "12350000", "12350000", 12350000}, + {23454999, 4, "23450000", "23450000", "23460000", 23450000}, + {23455000, 4, "23450000", "23460000", "23460000", 23460000}, + {23455001, 4, "23450000", "23460000", "23460000", 23460000}, + + {99994999, 4, "99990000", "99990000", "100000000", 99990000}, + {99995000, 4, "99990000", "100000000", "100000000", 100000000}, + {99999999, 4, "99990000", "100000000", "100000000", 100000000}, + + {12994999, 4, "12990000", "12990000", "13000000", 12990000}, + {12995000, 4, "12990000", "13000000", "13000000", 13000000}, + {12999999, 4, "12990000", "13000000", "13000000", 13000000}, +} + +func TestDecimalRound(t *testing.T) { + for i := 0; i < len(roundtests); i++ { + test := &roundtests[i] + d := NewDecimal(test.i) + d.RoundDown(test.nd) + s := d.String() + if s != test.down { + t.Errorf("Decimal %v RoundDown %d = %v, want %v", + test.i, test.nd, s, test.down) + } + d = NewDecimal(test.i) + d.Round(test.nd) + s = d.String() + if s != test.round { + t.Errorf("Decimal %v Round %d = %v, want %v", + test.i, test.nd, s, test.down) + } + d = NewDecimal(test.i) + d.RoundUp(test.nd) + s = d.String() + if s != test.up { + t.Errorf("Decimal %v RoundUp %d = %v, want %v", + test.i, test.nd, s, test.up) + } + } +} + +type roundIntTest struct { + i uint64 + shift int + int uint64 +} + +var roundinttests = []roundIntTest{ + {0, 100, 0}, + {512, -8, 2}, + {513, -8, 2}, + {640, -8, 2}, + {641, -8, 3}, + {384, -8, 2}, + {385, -8, 2}, + {383, -8, 1}, + {1, 100, 1<<64 - 1}, + {1000, 0, 1000}, +} + +func TestDecimalRoundedInteger(t *testing.T) { + for i := 0; i < len(roundinttests); i++ { + test := roundinttests[i] + d := NewDecimal(test.i) + d.Shift(test.shift) + num := d.RoundedInteger() + if num != test.int { + t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v", + test.i, test.shift, num, test.int) + } + } +} diff --git a/gnovm/stdlibs/strconv/doc.gno b/gnovm/stdlibs/strconv/doc.gno new file mode 100644 index 00000000000..9a22d77a0cd --- /dev/null +++ b/gnovm/stdlibs/strconv/doc.gno @@ -0,0 +1,59 @@ +// Copyright 2015 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 strconv implements conversions to and from string representations +// of basic data types. +// +// # Numeric Conversions +// +// The most common numeric conversions are Atoi (string to int) and Itoa (int to string). +// +// i, err := strconv.Atoi("-42") +// s := strconv.Itoa(-42) +// +// These assume decimal and the Go int type. +// +// [ParseBool], [ParseFloat], [ParseInt], and [ParseUint] convert strings to values: +// +// b, err := strconv.ParseBool("true") +// f, err := strconv.ParseFloat("3.1415", 64) +// i, err := strconv.ParseInt("-42", 10, 64) +// u, err := strconv.ParseUint("42", 10, 64) +// +// The parse functions return the widest type (float64, int64, and uint64), +// but if the size argument specifies a narrower width the result can be +// converted to that narrower type without data loss: +// +// s := "2147483647" // biggest int32 +// i64, err := strconv.ParseInt(s, 10, 32) +// ... +// i := int32(i64) +// +// [FormatBool], [FormatFloat], [FormatInt], and [FormatUint] convert values to strings: +// +// s := strconv.FormatBool(true) +// s := strconv.FormatFloat(3.1415, 'E', -1, 64) +// s := strconv.FormatInt(-42, 16) +// s := strconv.FormatUint(42, 16) +// +// [AppendBool], [AppendFloat], [AppendInt], and [AppendUint] are similar but +// append the formatted value to a destination slice. +// +// # String Conversions +// +// [Quote] and [QuoteToASCII] convert strings to quoted Go string literals. +// The latter guarantees that the result is an ASCII string, by escaping +// any non-ASCII Unicode with \u: +// +// q := strconv.Quote("Hello, 世界") +// q := strconv.QuoteToASCII("Hello, 世界") +// +// [QuoteRune] and [QuoteRuneToASCII] are similar but accept runes and +// return quoted Go rune literals. +// +// [Unquote] and [UnquoteChar] unquote Go string and rune literals. +// +// XXX: Gno does not implement any of the functions from Go's strconv which +// pertain to complex numbers, such as FormatComplex and ParseComplex. +package strconv diff --git a/gnovm/stdlibs/strconv/eisel_lemire.gno b/gnovm/stdlibs/strconv/eisel_lemire.gno new file mode 100644 index 00000000000..03842e50797 --- /dev/null +++ b/gnovm/stdlibs/strconv/eisel_lemire.gno @@ -0,0 +1,884 @@ +// Copyright 2020 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 strconv + +// This file implements the Eisel-Lemire ParseFloat algorithm, published in +// 2020 and discussed extensively at +// https://nigeltao.github.io/blog/2020/eisel-lemire.html +// +// The original C++ implementation is at +// https://github.com/lemire/fast_double_parser/blob/644bef4306059d3be01a04e77d3cc84b379c596f/include/fast_double_parser.h#L840 +// +// This Go re-implementation closely follows the C re-implementation at +// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/internal/cgen/base/floatconv-submodule-code.c#L990 +// +// Additional testing (on over several million test strings) is done by +// https://github.com/nigeltao/parse-number-fxx-test-data/blob/5280dcfccf6d0b02a65ae282dad0b6d9de50e039/script/test-go-strconv.go + +import ( + "math" + "math/bits" +) + +func eiselLemire64(man uint64, exp10 int, neg bool) (f float64, ok bool) { + // The terse comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + + // Exp10 Range. + if man == 0 { + if neg { + f = math.Float64frombits(0x8000000000000000) // Negative zero. + } + return f, true + } + if exp10 < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < exp10 { + return 0, false + } + + // Normalization. + clz := bits.LeadingZeros64(man) + man <<= uint(clz) + const float64ExponentBias = 1023 + retExp2 := uint64(217706*exp10>>16+64+float64ExponentBias) - uint64(clz) + + // Multiplication. + xHi, xLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][1]) + + // Wider Approximation. + if xHi&0x1FF == 0x1FF && xLo+man < man { + yHi, yLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][0]) + mergedHi, mergedLo := xHi, xLo+yHi + if mergedLo < xLo { + mergedHi++ + } + if mergedHi&0x1FF == 0x1FF && mergedLo+1 == 0 && yLo+man < man { + return 0, false + } + xHi, xLo = mergedHi, mergedLo + } + + // Shifting to 54 Bits. + msb := xHi >> 63 + retMantissa := xHi >> (msb + 9) + retExp2 -= 1 ^ msb + + // Half-way Ambiguity. + if xLo == 0 && xHi&0x1FF == 0 && retMantissa&3 == 1 { + return 0, false + } + + // From 54 to 53 Bits. + retMantissa += retMantissa & 1 + retMantissa >>= 1 + if retMantissa>>53 > 0 { + retMantissa >>= 1 + retExp2 += 1 + } + // retExp2 is a uint64. Zero or underflow means that we're in subnormal + // float64 space. 0x7FF or above means that we're in Inf/NaN float64 space. + // + // The if block is equivalent to (but has fewer branches than): + // if retExp2 <= 0 || retExp2 >= 0x7FF { etc } + if retExp2-1 >= 0x7FF-1 { + return 0, false + } + retBits := retExp2<<52 | retMantissa&0x000FFFFFFFFFFFFF + if neg { + retBits |= 0x8000000000000000 + } + return math.Float64frombits(retBits), true +} + +func eiselLemire32(man uint64, exp10 int, neg bool) (f float32, ok bool) { + // The terse comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + // + // That blog post discusses the float64 flavor (11 exponent bits with a + // -1023 bias, 52 mantissa bits) of the algorithm, but the same approach + // applies to the float32 flavor (8 exponent bits with a -127 bias, 23 + // mantissa bits). The computation here happens with 64-bit values (e.g. + // man, xHi, retMantissa) before finally converting to a 32-bit float. + + // Exp10 Range. + if man == 0 { + if neg { + f = math.Float32frombits(0x80000000) // Negative zero. + } + return f, true + } + if exp10 < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < exp10 { + return 0, false + } + + // Normalization. + clz := bits.LeadingZeros64(man) + man <<= uint(clz) + const float32ExponentBias = 127 + retExp2 := uint64(217706*exp10>>16+64+float32ExponentBias) - uint64(clz) + + // Multiplication. + xHi, xLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][1]) + + // Wider Approximation. + if xHi&0x3FFFFFFFFF == 0x3FFFFFFFFF && xLo+man < man { + yHi, yLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][0]) + mergedHi, mergedLo := xHi, xLo+yHi + if mergedLo < xLo { + mergedHi++ + } + if mergedHi&0x3FFFFFFFFF == 0x3FFFFFFFFF && mergedLo+1 == 0 && yLo+man < man { + return 0, false + } + xHi, xLo = mergedHi, mergedLo + } + + // Shifting to 54 Bits (and for float32, it's shifting to 25 bits). + msb := xHi >> 63 + retMantissa := xHi >> (msb + 38) + retExp2 -= 1 ^ msb + + // Half-way Ambiguity. + if xLo == 0 && xHi&0x3FFFFFFFFF == 0 && retMantissa&3 == 1 { + return 0, false + } + + // From 54 to 53 Bits (and for float32, it's from 25 to 24 bits). + retMantissa += retMantissa & 1 + retMantissa >>= 1 + if retMantissa>>24 > 0 { + retMantissa >>= 1 + retExp2 += 1 + } + // retExp2 is a uint64. Zero or underflow means that we're in subnormal + // float32 space. 0xFF or above means that we're in Inf/NaN float32 space. + // + // The if block is equivalent to (but has fewer branches than): + // if retExp2 <= 0 || retExp2 >= 0xFF { etc } + if retExp2-1 >= 0xFF-1 { + return 0, false + } + retBits := retExp2<<23 | retMantissa&0x007FFFFF + if neg { + retBits |= 0x80000000 + } + return math.Float32frombits(uint32(retBits)), true +} + +// detailedPowersOfTen{Min,Max}Exp10 is the power of 10 represented by the +// first and last rows of detailedPowersOfTen. Both bounds are inclusive. +const ( + detailedPowersOfTenMinExp10 = -348 + detailedPowersOfTenMaxExp10 = +347 +) + +// detailedPowersOfTen contains 128-bit mantissa approximations (rounded down) +// to the powers of 10. For example: +// +// - 1e43 ≈ (0xE596B7B0_C643C719 * (2 ** 79)) +// - 1e43 = (0xE596B7B0_C643C719_6D9CCD05_D0000000 * (2 ** 15)) +// +// The mantissas are explicitly listed. The exponents are implied by a linear +// expression with slope 217706.0/65536.0 ≈ log(10)/log(2). +// +// The table was generated by +// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/script/print-mpb-powers-of-10.go +var detailedPowersOfTen = [...][2]uint64{ + {0x1732C869CD60E453, 0xFA8FD5A0081C0288}, // 1e-348 + {0x0E7FBD42205C8EB4, 0x9C99E58405118195}, // 1e-347 + {0x521FAC92A873B261, 0xC3C05EE50655E1FA}, // 1e-346 + {0xE6A797B752909EF9, 0xF4B0769E47EB5A78}, // 1e-345 + {0x9028BED2939A635C, 0x98EE4A22ECF3188B}, // 1e-344 + {0x7432EE873880FC33, 0xBF29DCABA82FDEAE}, // 1e-343 + {0x113FAA2906A13B3F, 0xEEF453D6923BD65A}, // 1e-342 + {0x4AC7CA59A424C507, 0x9558B4661B6565F8}, // 1e-341 + {0x5D79BCF00D2DF649, 0xBAAEE17FA23EBF76}, // 1e-340 + {0xF4D82C2C107973DC, 0xE95A99DF8ACE6F53}, // 1e-339 + {0x79071B9B8A4BE869, 0x91D8A02BB6C10594}, // 1e-338 + {0x9748E2826CDEE284, 0xB64EC836A47146F9}, // 1e-337 + {0xFD1B1B2308169B25, 0xE3E27A444D8D98B7}, // 1e-336 + {0xFE30F0F5E50E20F7, 0x8E6D8C6AB0787F72}, // 1e-335 + {0xBDBD2D335E51A935, 0xB208EF855C969F4F}, // 1e-334 + {0xAD2C788035E61382, 0xDE8B2B66B3BC4723}, // 1e-333 + {0x4C3BCB5021AFCC31, 0x8B16FB203055AC76}, // 1e-332 + {0xDF4ABE242A1BBF3D, 0xADDCB9E83C6B1793}, // 1e-331 + {0xD71D6DAD34A2AF0D, 0xD953E8624B85DD78}, // 1e-330 + {0x8672648C40E5AD68, 0x87D4713D6F33AA6B}, // 1e-329 + {0x680EFDAF511F18C2, 0xA9C98D8CCB009506}, // 1e-328 + {0x0212BD1B2566DEF2, 0xD43BF0EFFDC0BA48}, // 1e-327 + {0x014BB630F7604B57, 0x84A57695FE98746D}, // 1e-326 + {0x419EA3BD35385E2D, 0xA5CED43B7E3E9188}, // 1e-325 + {0x52064CAC828675B9, 0xCF42894A5DCE35EA}, // 1e-324 + {0x7343EFEBD1940993, 0x818995CE7AA0E1B2}, // 1e-323 + {0x1014EBE6C5F90BF8, 0xA1EBFB4219491A1F}, // 1e-322 + {0xD41A26E077774EF6, 0xCA66FA129F9B60A6}, // 1e-321 + {0x8920B098955522B4, 0xFD00B897478238D0}, // 1e-320 + {0x55B46E5F5D5535B0, 0x9E20735E8CB16382}, // 1e-319 + {0xEB2189F734AA831D, 0xC5A890362FDDBC62}, // 1e-318 + {0xA5E9EC7501D523E4, 0xF712B443BBD52B7B}, // 1e-317 + {0x47B233C92125366E, 0x9A6BB0AA55653B2D}, // 1e-316 + {0x999EC0BB696E840A, 0xC1069CD4EABE89F8}, // 1e-315 + {0xC00670EA43CA250D, 0xF148440A256E2C76}, // 1e-314 + {0x380406926A5E5728, 0x96CD2A865764DBCA}, // 1e-313 + {0xC605083704F5ECF2, 0xBC807527ED3E12BC}, // 1e-312 + {0xF7864A44C633682E, 0xEBA09271E88D976B}, // 1e-311 + {0x7AB3EE6AFBE0211D, 0x93445B8731587EA3}, // 1e-310 + {0x5960EA05BAD82964, 0xB8157268FDAE9E4C}, // 1e-309 + {0x6FB92487298E33BD, 0xE61ACF033D1A45DF}, // 1e-308 + {0xA5D3B6D479F8E056, 0x8FD0C16206306BAB}, // 1e-307 + {0x8F48A4899877186C, 0xB3C4F1BA87BC8696}, // 1e-306 + {0x331ACDABFE94DE87, 0xE0B62E2929ABA83C}, // 1e-305 + {0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925}, // 1e-304 + {0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F}, // 1e-303 + {0xC9E82CD9F69D6150, 0xDB71E91432B1A24A}, // 1e-302 + {0xBE311C083A225CD2, 0x892731AC9FAF056E}, // 1e-301 + {0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA}, // 1e-300 + {0x092CBBCCDAD5B108, 0xD64D3D9DB981787D}, // 1e-299 + {0x25BBF56008C58EA5, 0x85F0468293F0EB4E}, // 1e-298 + {0xAF2AF2B80AF6F24E, 0xA76C582338ED2621}, // 1e-297 + {0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA}, // 1e-296 + {0x50D98D9FC890ED4D, 0x82CCA4DB847945CA}, // 1e-295 + {0xE50FF107BAB528A0, 0xA37FCE126597973C}, // 1e-294 + {0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C}, // 1e-293 + {0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F}, // 1e-292 + {0x77B191618C54E9AC, 0x9FAACF3DF73609B1}, // 1e-291 + {0xD59DF5B9EF6A2417, 0xC795830D75038C1D}, // 1e-290 + {0x4B0573286B44AD1D, 0xF97AE3D0D2446F25}, // 1e-289 + {0x4EE367F9430AEC32, 0x9BECCE62836AC577}, // 1e-288 + {0x229C41F793CDA73F, 0xC2E801FB244576D5}, // 1e-287 + {0x6B43527578C1110F, 0xF3A20279ED56D48A}, // 1e-286 + {0x830A13896B78AAA9, 0x9845418C345644D6}, // 1e-285 + {0x23CC986BC656D553, 0xBE5691EF416BD60C}, // 1e-284 + {0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F}, // 1e-283 + {0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39}, // 1e-282 + {0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07}, // 1e-281 + {0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9}, // 1e-280 + {0x23100809B9C21FA1, 0x91376C36D99995BE}, // 1e-279 + {0xABD40A0C2832A78A, 0xB58547448FFFFB2D}, // 1e-278 + {0x16C90C8F323F516C, 0xE2E69915B3FFF9F9}, // 1e-277 + {0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B}, // 1e-276 + {0x99CD11CFDF41779C, 0xB1442798F49FFB4A}, // 1e-275 + {0x40405643D711D583, 0xDD95317F31C7FA1D}, // 1e-274 + {0x482835EA666B2572, 0x8A7D3EEF7F1CFC52}, // 1e-273 + {0xDA3243650005EECF, 0xAD1C8EAB5EE43B66}, // 1e-272 + {0x90BED43E40076A82, 0xD863B256369D4A40}, // 1e-271 + {0x5A7744A6E804A291, 0x873E4F75E2224E68}, // 1e-270 + {0x711515D0A205CB36, 0xA90DE3535AAAE202}, // 1e-269 + {0x0D5A5B44CA873E03, 0xD3515C2831559A83}, // 1e-268 + {0xE858790AFE9486C2, 0x8412D9991ED58091}, // 1e-267 + {0x626E974DBE39A872, 0xA5178FFF668AE0B6}, // 1e-266 + {0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3}, // 1e-265 + {0x7CE66634BC9D0B99, 0x80FA687F881C7F8E}, // 1e-264 + {0x1C1FFFC1EBC44E80, 0xA139029F6A239F72}, // 1e-263 + {0xA327FFB266B56220, 0xC987434744AC874E}, // 1e-262 + {0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922}, // 1e-261 + {0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5}, // 1e-260 + {0xCB550FB4384D21D3, 0xC4CE17B399107C22}, // 1e-259 + {0x7E2A53A146606A48, 0xF6019DA07F549B2B}, // 1e-258 + {0x2EDA7444CBFC426D, 0x99C102844F94E0FB}, // 1e-257 + {0xFA911155FEFB5308, 0xC0314325637A1939}, // 1e-256 + {0x793555AB7EBA27CA, 0xF03D93EEBC589F88}, // 1e-255 + {0x4BC1558B2F3458DE, 0x96267C7535B763B5}, // 1e-254 + {0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2}, // 1e-253 + {0x465E15A979C1CADC, 0xEA9C227723EE8BCB}, // 1e-252 + {0x0BFACD89EC191EC9, 0x92A1958A7675175F}, // 1e-251 + {0xCEF980EC671F667B, 0xB749FAED14125D36}, // 1e-250 + {0x82B7E12780E7401A, 0xE51C79A85916F484}, // 1e-249 + {0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2}, // 1e-248 + {0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07}, // 1e-247 + {0x67A791E093E1D49A, 0xDFBDCECE67006AC9}, // 1e-246 + {0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD}, // 1e-245 + {0x58FAE9F773886E18, 0xAECC49914078536D}, // 1e-244 + {0xAF39A475506A899E, 0xDA7F5BF590966848}, // 1e-243 + {0x6D8406C952429603, 0x888F99797A5E012D}, // 1e-242 + {0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178}, // 1e-241 + {0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6}, // 1e-240 + {0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26}, // 1e-239 + {0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F}, // 1e-238 + {0xF13B94DAF124DA26, 0xD0601D8EFC57B08B}, // 1e-237 + {0x76C53D08D6B70858, 0x823C12795DB6CE57}, // 1e-236 + {0x54768C4B0C64CA6E, 0xA2CB1717B52481ED}, // 1e-235 + {0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268}, // 1e-234 + {0xD3F93B35435D7C4C, 0xFE5D54150B090B02}, // 1e-233 + {0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1}, // 1e-232 + {0x359AB6419CA1091B, 0xC6B8E9B0709F109A}, // 1e-231 + {0xC30163D203C94B62, 0xF867241C8CC6D4C0}, // 1e-230 + {0x79E0DE63425DCF1D, 0x9B407691D7FC44F8}, // 1e-229 + {0x985915FC12F542E4, 0xC21094364DFB5636}, // 1e-228 + {0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4}, // 1e-227 + {0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A}, // 1e-226 + {0x50C6FF782A838353, 0xBD8430BD08277231}, // 1e-225 + {0xA4F8BF5635246428, 0xECE53CEC4A314EBD}, // 1e-224 + {0x871B7795E136BE99, 0x940F4613AE5ED136}, // 1e-223 + {0x28E2557B59846E3F, 0xB913179899F68584}, // 1e-222 + {0x331AEADA2FE589CF, 0xE757DD7EC07426E5}, // 1e-221 + {0x3FF0D2C85DEF7621, 0x9096EA6F3848984F}, // 1e-220 + {0x0FED077A756B53A9, 0xB4BCA50B065ABE63}, // 1e-219 + {0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB}, // 1e-218 + {0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD}, // 1e-217 + {0xBD8D794D96AACFB3, 0xB080392CC4349DEC}, // 1e-216 + {0xECF0D7A0FC5583A0, 0xDCA04777F541C567}, // 1e-215 + {0xF41686C49DB57244, 0x89E42CAAF9491B60}, // 1e-214 + {0x311C2875C522CED5, 0xAC5D37D5B79B6239}, // 1e-213 + {0x7D633293366B828B, 0xD77485CB25823AC7}, // 1e-212 + {0xAE5DFF9C02033197, 0x86A8D39EF77164BC}, // 1e-211 + {0xD9F57F830283FDFC, 0xA8530886B54DBDEB}, // 1e-210 + {0xD072DF63C324FD7B, 0xD267CAA862A12D66}, // 1e-209 + {0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60}, // 1e-208 + {0x52D9BE85F074E608, 0xA46116538D0DEB78}, // 1e-207 + {0x67902E276C921F8B, 0xCD795BE870516656}, // 1e-206 + {0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6}, // 1e-205 + {0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3}, // 1e-204 + {0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0}, // 1e-203 + {0x796B805720085F81, 0xFAD2A4B13D1B5D6C}, // 1e-202 + {0xCBE3303674053BB0, 0x9CC3A6EEC6311A63}, // 1e-201 + {0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC}, // 1e-200 + {0xEE92FB5515482D44, 0xF4F1B4D515ACB93B}, // 1e-199 + {0x751BDD152D4D1C4A, 0x991711052D8BF3C5}, // 1e-198 + {0xD262D45A78A0635D, 0xBF5CD54678EEF0B6}, // 1e-197 + {0x86FB897116C87C34, 0xEF340A98172AACE4}, // 1e-196 + {0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E}, // 1e-195 + {0x8974836059CCA109, 0xBAE0A846D2195712}, // 1e-194 + {0x2BD1A438703FC94B, 0xE998D258869FACD7}, // 1e-193 + {0x7B6306A34627DDCF, 0x91FF83775423CC06}, // 1e-192 + {0x1A3BC84C17B1D542, 0xB67F6455292CBF08}, // 1e-191 + {0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA}, // 1e-190 + {0x547EB47B7282EE9C, 0x8E938662882AF53E}, // 1e-189 + {0xE99E619A4F23AA43, 0xB23867FB2A35B28D}, // 1e-188 + {0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31}, // 1e-187 + {0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E}, // 1e-186 + {0x9624AB50B148D445, 0xAE0B158B4738705E}, // 1e-185 + {0x3BADD624DD9B0957, 0xD98DDAEE19068C76}, // 1e-184 + {0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9}, // 1e-183 + {0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC}, // 1e-182 + {0x7647C3200069671F, 0xD47487CC8470652B}, // 1e-181 + {0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B}, // 1e-180 + {0xF468107100525890, 0xA5FB0A17C777CF09}, // 1e-179 + {0x7182148D4066EEB4, 0xCF79CC9DB955C2CC}, // 1e-178 + {0xC6F14CD848405530, 0x81AC1FE293D599BF}, // 1e-177 + {0xB8ADA00E5A506A7C, 0xA21727DB38CB002F}, // 1e-176 + {0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B}, // 1e-175 + {0x908F4A166D1DA663, 0xFD442E4688BD304A}, // 1e-174 + {0x9A598E4E043287FE, 0x9E4A9CEC15763E2E}, // 1e-173 + {0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA}, // 1e-172 + {0xD12BEE59E68EF47C, 0xF7549530E188C128}, // 1e-171 + {0x82BB74F8301958CE, 0x9A94DD3E8CF578B9}, // 1e-170 + {0xE36A52363C1FAF01, 0xC13A148E3032D6E7}, // 1e-169 + {0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1}, // 1e-168 + {0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5}, // 1e-167 + {0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE}, // 1e-166 + {0x111B495B3464AD21, 0xEBDF661791D60F56}, // 1e-165 + {0xCAB10DD900BEEC34, 0x936B9FCEBB25C995}, // 1e-164 + {0x3D5D514F40EEA742, 0xB84687C269EF3BFB}, // 1e-163 + {0x0CB4A5A3112A5112, 0xE65829B3046B0AFA}, // 1e-162 + {0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC}, // 1e-161 + {0x59ED216765690F56, 0xB3F4E093DB73A093}, // 1e-160 + {0x306869C13EC3532C, 0xE0F218B8D25088B8}, // 1e-159 + {0x1E414218C73A13FB, 0x8C974F7383725573}, // 1e-158 + {0xE5D1929EF90898FA, 0xAFBD2350644EEACF}, // 1e-157 + {0xDF45F746B74ABF39, 0xDBAC6C247D62A583}, // 1e-156 + {0x6B8BBA8C328EB783, 0x894BC396CE5DA772}, // 1e-155 + {0x066EA92F3F326564, 0xAB9EB47C81F5114F}, // 1e-154 + {0xC80A537B0EFEFEBD, 0xD686619BA27255A2}, // 1e-153 + {0xBD06742CE95F5F36, 0x8613FD0145877585}, // 1e-152 + {0x2C48113823B73704, 0xA798FC4196E952E7}, // 1e-151 + {0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0}, // 1e-150 + {0x9A984D73DBE722FB, 0x82EF85133DE648C4}, // 1e-149 + {0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5}, // 1e-148 + {0x318DF905079926A8, 0xCC963FEE10B7D1B3}, // 1e-147 + {0xFDF17746497F7052, 0xFFBBCFE994E5C61F}, // 1e-146 + {0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3}, // 1e-145 + {0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8}, // 1e-144 + {0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B}, // 1e-143 + {0x06BEA10CA65C084E, 0x9C1661A651213E2D}, // 1e-142 + {0x486E494FCFF30A62, 0xC31BFA0FE5698DB8}, // 1e-141 + {0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126}, // 1e-140 + {0xF89629465A75E01C, 0x986DDB5C6B3A76B7}, // 1e-139 + {0xF6BBB397F1135823, 0xBE89523386091465}, // 1e-138 + {0x746AA07DED582E2C, 0xEE2BA6C0678B597F}, // 1e-137 + {0xA8C2A44EB4571CDC, 0x94DB483840B717EF}, // 1e-136 + {0x92F34D62616CE413, 0xBA121A4650E4DDEB}, // 1e-135 + {0x77B020BAF9C81D17, 0xE896A0D7E51E1566}, // 1e-134 + {0x0ACE1474DC1D122E, 0x915E2486EF32CD60}, // 1e-133 + {0x0D819992132456BA, 0xB5B5ADA8AAFF80B8}, // 1e-132 + {0x10E1FFF697ED6C69, 0xE3231912D5BF60E6}, // 1e-131 + {0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F}, // 1e-130 + {0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3}, // 1e-129 + {0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0}, // 1e-128 + {0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4}, // 1e-127 + {0x86C16C98D2C953C6, 0xAD4AB7112EB3929D}, // 1e-126 + {0xE871C7BF077BA8B7, 0xD89D64D57A607744}, // 1e-125 + {0x11471CD764AD4972, 0x87625F056C7C4A8B}, // 1e-124 + {0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D}, // 1e-123 + {0x4AFF1D108D4EC2C3, 0xD389B47879823479}, // 1e-122 + {0xCEDF722A585139BA, 0x843610CB4BF160CB}, // 1e-121 + {0xC2974EB4EE658828, 0xA54394FE1EEDB8FE}, // 1e-120 + {0x733D226229FEEA32, 0xCE947A3DA6A9273E}, // 1e-119 + {0x0806357D5A3F525F, 0x811CCC668829B887}, // 1e-118 + {0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8}, // 1e-117 + {0xFC89B393DD02F0B5, 0xC9BCFF6034C13052}, // 1e-116 + {0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67}, // 1e-115 + {0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0}, // 1e-114 + {0x0A9E795E65D4DF11, 0xC5029163F384A931}, // 1e-113 + {0x4D4617B5FF4A16D5, 0xF64335BCF065D37D}, // 1e-112 + {0x504BCED1BF8E4E45, 0x99EA0196163FA42E}, // 1e-111 + {0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39}, // 1e-110 + {0x5D767327BB4E5A4C, 0xF07DA27A82C37088}, // 1e-109 + {0x3A6A07F8D510F86F, 0x964E858C91BA2655}, // 1e-108 + {0x890489F70A55368B, 0xBBE226EFB628AFEA}, // 1e-107 + {0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5}, // 1e-106 + {0x3B0B8BC90012929D, 0x92C8AE6B464FC96F}, // 1e-105 + {0x09CE6EBB40173744, 0xB77ADA0617E3BBCB}, // 1e-104 + {0xCC420A6A101D0515, 0xE55990879DDCAABD}, // 1e-103 + {0x9FA946824A12232D, 0x8F57FA54C2A9EAB6}, // 1e-102 + {0x47939822DC96ABF9, 0xB32DF8E9F3546564}, // 1e-101 + {0x59787E2B93BC56F7, 0xDFF9772470297EBD}, // 1e-100 + {0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36}, // 1e-99 + {0xEDE622920B6B23F1, 0xAEFAE51477A06B03}, // 1e-98 + {0xE95FAB368E45ECED, 0xDAB99E59958885C4}, // 1e-97 + {0x11DBCB0218EBB414, 0x88B402F7FD75539B}, // 1e-96 + {0xD652BDC29F26A119, 0xAAE103B5FCD2A881}, // 1e-95 + {0x4BE76D3346F0495F, 0xD59944A37C0752A2}, // 1e-94 + {0x6F70A4400C562DDB, 0x857FCAE62D8493A5}, // 1e-93 + {0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E}, // 1e-92 + {0x7E2000A41346A7A7, 0xD097AD07A71F26B2}, // 1e-91 + {0x8ED400668C0C28C8, 0x825ECC24C873782F}, // 1e-90 + {0x728900802F0F32FA, 0xA2F67F2DFA90563B}, // 1e-89 + {0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA}, // 1e-88 + {0xE2F610C84987BFA8, 0xFEA126B7D78186BC}, // 1e-87 + {0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436}, // 1e-86 + {0x91503D1C79720DBB, 0xC6EDE63FA05D3143}, // 1e-85 + {0x75A44C6397CE912A, 0xF8A95FCF88747D94}, // 1e-84 + {0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C}, // 1e-83 + {0xFBE85BADCE996168, 0xC24452DA229B021B}, // 1e-82 + {0xFAE27299423FB9C3, 0xF2D56790AB41C2A2}, // 1e-81 + {0xDCCD879FC967D41A, 0x97C560BA6B0919A5}, // 1e-80 + {0x5400E987BBC1C920, 0xBDB6B8E905CB600F}, // 1e-79 + {0x290123E9AAB23B68, 0xED246723473E3813}, // 1e-78 + {0xF9A0B6720AAF6521, 0x9436C0760C86E30B}, // 1e-77 + {0xF808E40E8D5B3E69, 0xB94470938FA89BCE}, // 1e-76 + {0xB60B1D1230B20E04, 0xE7958CB87392C2C2}, // 1e-75 + {0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9}, // 1e-74 + {0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828}, // 1e-73 + {0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232}, // 1e-72 + {0x579C487E5A38AD0E, 0x8D590723948A535F}, // 1e-71 + {0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837}, // 1e-70 + {0xF8E431456CF88E65, 0xDCDB1B2798182244}, // 1e-69 + {0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B}, // 1e-68 + {0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5}, // 1e-67 + {0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177}, // 1e-66 + {0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA}, // 1e-65 + {0x3F2398D747B36224, 0xA87FEA27A539E9A5}, // 1e-64 + {0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E}, // 1e-63 + {0x1953CF68300424AC, 0x83A3EEEEF9153E89}, // 1e-62 + {0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B}, // 1e-61 + {0x3792F412CB06794D, 0xCDB02555653131B6}, // 1e-60 + {0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11}, // 1e-59 + {0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6}, // 1e-58 + {0xF245825A5A445275, 0xC8DE047564D20A8B}, // 1e-57 + {0xEED6E2F0F0D56712, 0xFB158592BE068D2E}, // 1e-56 + {0x55464DD69685606B, 0x9CED737BB6C4183D}, // 1e-55 + {0xAA97E14C3C26B886, 0xC428D05AA4751E4C}, // 1e-54 + {0xD53DD99F4B3066A8, 0xF53304714D9265DF}, // 1e-53 + {0xE546A8038EFE4029, 0x993FE2C6D07B7FAB}, // 1e-52 + {0xDE98520472BDD033, 0xBF8FDB78849A5F96}, // 1e-51 + {0x963E66858F6D4440, 0xEF73D256A5C0F77C}, // 1e-50 + {0xDDE7001379A44AA8, 0x95A8637627989AAD}, // 1e-49 + {0x5560C018580D5D52, 0xBB127C53B17EC159}, // 1e-48 + {0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF}, // 1e-47 + {0xCAB3961304CA70E8, 0x9226712162AB070D}, // 1e-46 + {0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1}, // 1e-45 + {0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05}, // 1e-44 + {0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3}, // 1e-43 + {0x55F038B237591ED3, 0xB267ED1940F1C61C}, // 1e-42 + {0x6B6C46DEC52F6688, 0xDF01E85F912E37A3}, // 1e-41 + {0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6}, // 1e-40 + {0xABEC975E0A0D081A, 0xAE397D8AA96C1B77}, // 1e-39 + {0x96E7BD358C904A21, 0xD9C7DCED53C72255}, // 1e-38 + {0x7E50D64177DA2E54, 0x881CEA14545C7575}, // 1e-37 + {0xDDE50BD1D5D0B9E9, 0xAA242499697392D2}, // 1e-36 + {0x955E4EC64B44E864, 0xD4AD2DBFC3D07787}, // 1e-35 + {0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4}, // 1e-34 + {0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61}, // 1e-33 + {0x67DE18EDA5814AF2, 0xCFB11EAD453994BA}, // 1e-32 + {0x80EACF948770CED7, 0x81CEB32C4B43FCF4}, // 1e-31 + {0xA1258379A94D028D, 0xA2425FF75E14FC31}, // 1e-30 + {0x096EE45813A04330, 0xCAD2F7F5359A3B3E}, // 1e-29 + {0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D}, // 1e-28 + {0x775EA264CF55347D, 0x9E74D1B791E07E48}, // 1e-27 + {0x95364AFE032A819D, 0xC612062576589DDA}, // 1e-26 + {0x3A83DDBD83F52204, 0xF79687AED3EEC551}, // 1e-25 + {0xC4926A9672793542, 0x9ABE14CD44753B52}, // 1e-24 + {0x75B7053C0F178293, 0xC16D9A0095928A27}, // 1e-23 + {0x5324C68B12DD6338, 0xF1C90080BAF72CB1}, // 1e-22 + {0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE}, // 1e-21 + {0x88F4BB1CA6BCF584, 0xBCE5086492111AEA}, // 1e-20 + {0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5}, // 1e-19 + {0x3AFF322E62439FCF, 0x9392EE8E921D5D07}, // 1e-18 + {0x09BEFEB9FAD487C2, 0xB877AA3236A4B449}, // 1e-17 + {0x4C2EBE687989A9B3, 0xE69594BEC44DE15B}, // 1e-16 + {0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9}, // 1e-15 + {0x538484C19EF38C94, 0xB424DC35095CD80F}, // 1e-14 + {0x2865A5F206B06FB9, 0xE12E13424BB40E13}, // 1e-13 + {0xF93F87B7442E45D3, 0x8CBCCC096F5088CB}, // 1e-12 + {0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE}, // 1e-11 + {0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE}, // 1e-10 + {0x31680A88F8953030, 0x89705F4136B4A597}, // 1e-9 + {0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC}, // 1e-8 + {0x3D32907604691B4C, 0xD6BF94D5E57A42BC}, // 1e-7 + {0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5}, // 1e-6 + {0x0FCF80DC33721D53, 0xA7C5AC471B478423}, // 1e-5 + {0xD3C36113404EA4A8, 0xD1B71758E219652B}, // 1e-4 + {0x645A1CAC083126E9, 0x83126E978D4FDF3B}, // 1e-3 + {0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A}, // 1e-2 + {0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC}, // 1e-1 + {0x0000000000000000, 0x8000000000000000}, // 1e0 + {0x0000000000000000, 0xA000000000000000}, // 1e1 + {0x0000000000000000, 0xC800000000000000}, // 1e2 + {0x0000000000000000, 0xFA00000000000000}, // 1e3 + {0x0000000000000000, 0x9C40000000000000}, // 1e4 + {0x0000000000000000, 0xC350000000000000}, // 1e5 + {0x0000000000000000, 0xF424000000000000}, // 1e6 + {0x0000000000000000, 0x9896800000000000}, // 1e7 + {0x0000000000000000, 0xBEBC200000000000}, // 1e8 + {0x0000000000000000, 0xEE6B280000000000}, // 1e9 + {0x0000000000000000, 0x9502F90000000000}, // 1e10 + {0x0000000000000000, 0xBA43B74000000000}, // 1e11 + {0x0000000000000000, 0xE8D4A51000000000}, // 1e12 + {0x0000000000000000, 0x9184E72A00000000}, // 1e13 + {0x0000000000000000, 0xB5E620F480000000}, // 1e14 + {0x0000000000000000, 0xE35FA931A0000000}, // 1e15 + {0x0000000000000000, 0x8E1BC9BF04000000}, // 1e16 + {0x0000000000000000, 0xB1A2BC2EC5000000}, // 1e17 + {0x0000000000000000, 0xDE0B6B3A76400000}, // 1e18 + {0x0000000000000000, 0x8AC7230489E80000}, // 1e19 + {0x0000000000000000, 0xAD78EBC5AC620000}, // 1e20 + {0x0000000000000000, 0xD8D726B7177A8000}, // 1e21 + {0x0000000000000000, 0x878678326EAC9000}, // 1e22 + {0x0000000000000000, 0xA968163F0A57B400}, // 1e23 + {0x0000000000000000, 0xD3C21BCECCEDA100}, // 1e24 + {0x0000000000000000, 0x84595161401484A0}, // 1e25 + {0x0000000000000000, 0xA56FA5B99019A5C8}, // 1e26 + {0x0000000000000000, 0xCECB8F27F4200F3A}, // 1e27 + {0x4000000000000000, 0x813F3978F8940984}, // 1e28 + {0x5000000000000000, 0xA18F07D736B90BE5}, // 1e29 + {0xA400000000000000, 0xC9F2C9CD04674EDE}, // 1e30 + {0x4D00000000000000, 0xFC6F7C4045812296}, // 1e31 + {0xF020000000000000, 0x9DC5ADA82B70B59D}, // 1e32 + {0x6C28000000000000, 0xC5371912364CE305}, // 1e33 + {0xC732000000000000, 0xF684DF56C3E01BC6}, // 1e34 + {0x3C7F400000000000, 0x9A130B963A6C115C}, // 1e35 + {0x4B9F100000000000, 0xC097CE7BC90715B3}, // 1e36 + {0x1E86D40000000000, 0xF0BDC21ABB48DB20}, // 1e37 + {0x1314448000000000, 0x96769950B50D88F4}, // 1e38 + {0x17D955A000000000, 0xBC143FA4E250EB31}, // 1e39 + {0x5DCFAB0800000000, 0xEB194F8E1AE525FD}, // 1e40 + {0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE}, // 1e41 + {0xF14A3D9E40000000, 0xB7ABC627050305AD}, // 1e42 + {0x6D9CCD05D0000000, 0xE596B7B0C643C719}, // 1e43 + {0xE4820023A2000000, 0x8F7E32CE7BEA5C6F}, // 1e44 + {0xDDA2802C8A800000, 0xB35DBF821AE4F38B}, // 1e45 + {0xD50B2037AD200000, 0xE0352F62A19E306E}, // 1e46 + {0x4526F422CC340000, 0x8C213D9DA502DE45}, // 1e47 + {0x9670B12B7F410000, 0xAF298D050E4395D6}, // 1e48 + {0x3C0CDD765F114000, 0xDAF3F04651D47B4C}, // 1e49 + {0xA5880A69FB6AC800, 0x88D8762BF324CD0F}, // 1e50 + {0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053}, // 1e51 + {0x72A4904598D6D880, 0xD5D238A4ABE98068}, // 1e52 + {0x47A6DA2B7F864750, 0x85A36366EB71F041}, // 1e53 + {0x999090B65F67D924, 0xA70C3C40A64E6C51}, // 1e54 + {0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765}, // 1e55 + {0xBFF8F10E7A8921A4, 0x82818F1281ED449F}, // 1e56 + {0xAFF72D52192B6A0D, 0xA321F2D7226895C7}, // 1e57 + {0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39}, // 1e58 + {0x02F236D04753D5B4, 0xFEE50B7025C36A08}, // 1e59 + {0x01D762422C946590, 0x9F4F2726179A2245}, // 1e60 + {0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6}, // 1e61 + {0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B}, // 1e62 + {0x63CC55F49F88EB2F, 0x9B934C3B330C8577}, // 1e63 + {0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5}, // 1e64 + {0x8BEF464E3945EF7A, 0xF316271C7FC3908A}, // 1e65 + {0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56}, // 1e66 + {0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC}, // 1e67 + {0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27}, // 1e68 + {0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8}, // 1e69 + {0xB3E2FD538E122B44, 0xB975D6B6EE39E436}, // 1e70 + {0x60DBBCA87196B616, 0xE7D34C64A9C85D44}, // 1e71 + {0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A}, // 1e72 + {0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD}, // 1e73 + {0xC696963C7EED2DD1, 0xE264589A4DCDAB14}, // 1e74 + {0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC}, // 1e75 + {0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8}, // 1e76 + {0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912}, // 1e77 + {0x6E3569326C784337, 0x8A2DBF142DFCC7AB}, // 1e78 + {0x49C2C37F07965404, 0xACB92ED9397BF996}, // 1e79 + {0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB}, // 1e80 + {0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD}, // 1e81 + {0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC}, // 1e82 + {0xF50A3FA490C30190, 0xD2D80DB02AABD62B}, // 1e83 + {0x792667C6DA79E0FA, 0x83C7088E1AAB65DB}, // 1e84 + {0x577001B891185938, 0xA4B8CAB1A1563F52}, // 1e85 + {0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26}, // 1e86 + {0x544F8158315B05B4, 0x80B05E5AC60B6178}, // 1e87 + {0x696361AE3DB1C721, 0xA0DC75F1778E39D6}, // 1e88 + {0x03BC3A19CD1E38E9, 0xC913936DD571C84C}, // 1e89 + {0x04AB48A04065C723, 0xFB5878494ACE3A5F}, // 1e90 + {0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B}, // 1e91 + {0x3BA5D0BD324F8394, 0xC45D1DF942711D9A}, // 1e92 + {0xCA8F44EC7EE36479, 0xF5746577930D6500}, // 1e93 + {0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20}, // 1e94 + {0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8}, // 1e95 + {0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2}, // 1e96 + {0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5}, // 1e97 + {0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F}, // 1e98 + {0xF52D09D71A3293BD, 0xEA1575143CF97226}, // 1e99 + {0x593C2626705F9C56, 0x924D692CA61BE758}, // 1e100 + {0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E}, // 1e101 + {0x0B6DFB9C0F956447, 0xE498F455C38B997A}, // 1e102 + {0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC}, // 1e103 + {0x58EDEC91EC2CB657, 0xB2977EE300C50FE7}, // 1e104 + {0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1}, // 1e105 + {0xBD79E0D20082EE74, 0x8B865B215899F46C}, // 1e106 + {0xECD8590680A3AA11, 0xAE67F1E9AEC07187}, // 1e107 + {0xE80E6F4820CC9495, 0xDA01EE641A708DE9}, // 1e108 + {0x3109058D147FDCDD, 0x884134FE908658B2}, // 1e109 + {0xBD4B46F0599FD415, 0xAA51823E34A7EEDE}, // 1e110 + {0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96}, // 1e111 + {0x03E2CF6BC604DDB0, 0x850FADC09923329E}, // 1e112 + {0x84DB8346B786151C, 0xA6539930BF6BFF45}, // 1e113 + {0xE612641865679A63, 0xCFE87F7CEF46FF16}, // 1e114 + {0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E}, // 1e115 + {0xE3BE5E330F38F09D, 0xA26DA3999AEF7749}, // 1e116 + {0x5CADF5BFD3072CC5, 0xCB090C8001AB551C}, // 1e117 + {0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63}, // 1e118 + {0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E}, // 1e119 + {0xB281E1FD541501B8, 0xC646D63501A1511D}, // 1e120 + {0x1F225A7CA91A4226, 0xF7D88BC24209A565}, // 1e121 + {0x3375788DE9B06958, 0x9AE757596946075F}, // 1e122 + {0x0052D6B1641C83AE, 0xC1A12D2FC3978937}, // 1e123 + {0xC0678C5DBD23A49A, 0xF209787BB47D6B84}, // 1e124 + {0xF840B7BA963646E0, 0x9745EB4D50CE6332}, // 1e125 + {0xB650E5A93BC3D898, 0xBD176620A501FBFF}, // 1e126 + {0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF}, // 1e127 + {0xC66F336C36B10137, 0x93BA47C980E98CDF}, // 1e128 + {0xB80B0047445D4184, 0xB8A8D9BBE123F017}, // 1e129 + {0xA60DC059157491E5, 0xE6D3102AD96CEC1D}, // 1e130 + {0x87C89837AD68DB2F, 0x9043EA1AC7E41392}, // 1e131 + {0x29BABE4598C311FB, 0xB454E4A179DD1877}, // 1e132 + {0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94}, // 1e133 + {0x1899E4A65F58660C, 0x8CE2529E2734BB1D}, // 1e134 + {0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4}, // 1e135 + {0x76707543F4FA1F73, 0xDC21A1171D42645D}, // 1e136 + {0x6A06494A791C53A8, 0x899504AE72497EBA}, // 1e137 + {0x0487DB9D17636892, 0xABFA45DA0EDBDE69}, // 1e138 + {0x45A9D2845D3C42B6, 0xD6F8D7509292D603}, // 1e139 + {0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2}, // 1e140 + {0x8E6CAC7768D7141E, 0xA7F26836F282B732}, // 1e141 + {0x3207D795430CD926, 0xD1EF0244AF2364FF}, // 1e142 + {0x7F44E6BD49E807B8, 0x8335616AED761F1F}, // 1e143 + {0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7}, // 1e144 + {0x36DBA887C37A8C0F, 0xCD036837130890A1}, // 1e145 + {0xC2494954DA2C9789, 0x802221226BE55A64}, // 1e146 + {0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD}, // 1e147 + {0x6F92829494E5ACC7, 0xC83553C5C8965D3D}, // 1e148 + {0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C}, // 1e149 + {0xFF2A760414536EFB, 0x9C69A97284B578D7}, // 1e150 + {0xFEF5138519684ABA, 0xC38413CF25E2D70D}, // 1e151 + {0x7EB258665FC25D69, 0xF46518C2EF5B8CD1}, // 1e152 + {0xEF2F773FFBD97A61, 0x98BF2F79D5993802}, // 1e153 + {0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603}, // 1e154 + {0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784}, // 1e155 + {0xDD945A747BF26183, 0x952AB45CFA97A0B2}, // 1e156 + {0x94F971119AEEF9E4, 0xBA756174393D88DF}, // 1e157 + {0x7A37CD5601AAB85D, 0xE912B9D1478CEB17}, // 1e158 + {0xAC62E055C10AB33A, 0x91ABB422CCB812EE}, // 1e159 + {0x577B986B314D6009, 0xB616A12B7FE617AA}, // 1e160 + {0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94}, // 1e161 + {0x14588F13BE847307, 0x8E41ADE9FBEBC27D}, // 1e162 + {0x596EB2D8AE258FC8, 0xB1D219647AE6B31C}, // 1e163 + {0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3}, // 1e164 + {0x25DE7BB9480D5854, 0x8AEC23D680043BEE}, // 1e165 + {0xAF561AA79A10AE6A, 0xADA72CCC20054AE9}, // 1e166 + {0x1B2BA1518094DA04, 0xD910F7FF28069DA4}, // 1e167 + {0x90FB44D2F05D0842, 0x87AA9AFF79042286}, // 1e168 + {0x353A1607AC744A53, 0xA99541BF57452B28}, // 1e169 + {0x42889B8997915CE8, 0xD3FA922F2D1675F2}, // 1e170 + {0x69956135FEBADA11, 0x847C9B5D7C2E09B7}, // 1e171 + {0x43FAB9837E699095, 0xA59BC234DB398C25}, // 1e172 + {0x94F967E45E03F4BB, 0xCF02B2C21207EF2E}, // 1e173 + {0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D}, // 1e174 + {0x6462D92A69731732, 0xA1BA1BA79E1632DC}, // 1e175 + {0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93}, // 1e176 + {0x5CDA735244C3D43E, 0xFCB2CB35E702AF78}, // 1e177 + {0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB}, // 1e178 + {0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916}, // 1e179 + {0x8AAD549E57273D45, 0xF6C69A72A3989F5B}, // 1e180 + {0x36AC54E2F678864B, 0x9A3C2087A63F6399}, // 1e181 + {0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F}, // 1e182 + {0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F}, // 1e183 + {0x9F644AE5A4B1B325, 0x969EB7C47859E743}, // 1e184 + {0x873D5D9F0DDE1FEE, 0xBC4665B596706114}, // 1e185 + {0xA90CB506D155A7EA, 0xEB57FF22FC0C7959}, // 1e186 + {0x09A7F12442D588F2, 0x9316FF75DD87CBD8}, // 1e187 + {0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE}, // 1e188 + {0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81}, // 1e189 + {0xF96E017D694487BC, 0x8FA475791A569D10}, // 1e190 + {0x37C981DCC395A9AC, 0xB38D92D760EC4455}, // 1e191 + {0x85BBE253F47B1417, 0xE070F78D3927556A}, // 1e192 + {0x93956D7478CCEC8E, 0x8C469AB843B89562}, // 1e193 + {0x387AC8D1970027B2, 0xAF58416654A6BABB}, // 1e194 + {0x06997B05FCC0319E, 0xDB2E51BFE9D0696A}, // 1e195 + {0x441FECE3BDF81F03, 0x88FCF317F22241E2}, // 1e196 + {0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A}, // 1e197 + {0x8A71E223D8D3B074, 0xD60B3BD56A5586F1}, // 1e198 + {0xF6872D5667844E49, 0x85C7056562757456}, // 1e199 + {0xB428F8AC016561DB, 0xA738C6BEBB12D16C}, // 1e200 + {0xE13336D701BEBA52, 0xD106F86E69D785C7}, // 1e201 + {0xECC0024661173473, 0x82A45B450226B39C}, // 1e202 + {0x27F002D7F95D0190, 0xA34D721642B06084}, // 1e203 + {0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5}, // 1e204 + {0x7E67047175A15271, 0xFF290242C83396CE}, // 1e205 + {0x0F0062C6E984D386, 0x9F79A169BD203E41}, // 1e206 + {0x52C07B78A3E60868, 0xC75809C42C684DD1}, // 1e207 + {0xA7709A56CCDF8A82, 0xF92E0C3537826145}, // 1e208 + {0x88A66076400BB691, 0x9BBCC7A142B17CCB}, // 1e209 + {0x6ACFF893D00EA435, 0xC2ABF989935DDBFE}, // 1e210 + {0x0583F6B8C4124D43, 0xF356F7EBF83552FE}, // 1e211 + {0xC3727A337A8B704A, 0x98165AF37B2153DE}, // 1e212 + {0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6}, // 1e213 + {0x1162DEF06F79DF73, 0xEDA2EE1C7064130C}, // 1e214 + {0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7}, // 1e215 + {0x6D953E2BD7173692, 0xB9A74A0637CE2EE1}, // 1e216 + {0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99}, // 1e217 + {0x1D9C9892400A22A2, 0x910AB1D4DB9914A0}, // 1e218 + {0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8}, // 1e219 + {0x2E44AE64840FD61D, 0xE2A0B5DC971F303A}, // 1e220 + {0x5CEAECFED289E5D2, 0x8DA471A9DE737E24}, // 1e221 + {0x7425A83E872C5F47, 0xB10D8E1456105DAD}, // 1e222 + {0xD12F124E28F77719, 0xDD50F1996B947518}, // 1e223 + {0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F}, // 1e224 + {0x636CC64D1001550B, 0xACE73CBFDC0BFB7B}, // 1e225 + {0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A}, // 1e226 + {0x65ACFAEC34810A71, 0x8714A775E3E95C78}, // 1e227 + {0x7F1839A741A14D0D, 0xA8D9D1535CE3B396}, // 1e228 + {0x1EDE48111209A050, 0xD31045A8341CA07C}, // 1e229 + {0x934AED0AAB460432, 0x83EA2B892091E44D}, // 1e230 + {0xF81DA84D5617853F, 0xA4E4B66B68B65D60}, // 1e231 + {0x36251260AB9D668E, 0xCE1DE40642E3F4B9}, // 1e232 + {0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3}, // 1e233 + {0xB24CF65B8612F81F, 0xA1075A24E4421730}, // 1e234 + {0xDEE033F26797B627, 0xC94930AE1D529CFC}, // 1e235 + {0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C}, // 1e236 + {0x8E1F289560EE864E, 0x9D412E0806E88AA5}, // 1e237 + {0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E}, // 1e238 + {0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2}, // 1e239 + {0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765}, // 1e240 + {0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F}, // 1e241 + {0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E}, // 1e242 + {0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9}, // 1e243 + {0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F}, // 1e244 + {0x84C86189216DC5ED, 0xEA53DF5FD18D5513}, // 1e245 + {0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C}, // 1e246 + {0x3FBC8C33221DC2A1, 0xB7118682DBB66A77}, // 1e247 + {0x0FABAF3FEAA5334A, 0xE4D5E82392A40515}, // 1e248 + {0x29CB4D87F2A7400E, 0x8F05B1163BA6832D}, // 1e249 + {0x743E20E9EF511012, 0xB2C71D5BCA9023F8}, // 1e250 + {0x914DA9246B255416, 0xDF78E4B2BD342CF6}, // 1e251 + {0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A}, // 1e252 + {0xA184AC2473B529B1, 0xAE9672ABA3D0C320}, // 1e253 + {0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8}, // 1e254 + {0x7E2FA67C7A658892, 0x8865899617FB1871}, // 1e255 + {0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D}, // 1e256 + {0x552A74227F3EA565, 0xD51EA6FA85785631}, // 1e257 + {0xD53A88958F87275F, 0x8533285C936B35DE}, // 1e258 + {0x8A892ABAF368F137, 0xA67FF273B8460356}, // 1e259 + {0x2D2B7569B0432D85, 0xD01FEF10A657842C}, // 1e260 + {0x9C3B29620E29FC73, 0x8213F56A67F6B29B}, // 1e261 + {0x8349F3BA91B47B8F, 0xA298F2C501F45F42}, // 1e262 + {0x241C70A936219A73, 0xCB3F2F7642717713}, // 1e263 + {0xED238CD383AA0110, 0xFE0EFB53D30DD4D7}, // 1e264 + {0xF4363804324A40AA, 0x9EC95D1463E8A506}, // 1e265 + {0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48}, // 1e266 + {0xDD94B7868E94050A, 0xF81AA16FDC1B81DA}, // 1e267 + {0xCA7CF2B4191C8326, 0x9B10A4E5E9913128}, // 1e268 + {0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72}, // 1e269 + {0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF}, // 1e270 + {0xD5BE0503E085D813, 0x976E41088617CA01}, // 1e271 + {0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82}, // 1e272 + {0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2}, // 1e273 + {0xCABB90E5C942B503, 0x93E1AB8252F33B45}, // 1e274 + {0x3D6A751F3B936243, 0xB8DA1662E7B00A17}, // 1e275 + {0x0CC512670A783AD4, 0xE7109BFBA19C0C9D}, // 1e276 + {0x27FB2B80668B24C5, 0x906A617D450187E2}, // 1e277 + {0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA}, // 1e278 + {0x5E7873F8A0396973, 0xE1A63853BBD26451}, // 1e279 + {0xDB0B487B6423E1E8, 0x8D07E33455637EB2}, // 1e280 + {0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F}, // 1e281 + {0x7641A140CC7810FB, 0xDC5C5301C56B75F7}, // 1e282 + {0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA}, // 1e283 + {0x546345FA9FBDCD44, 0xAC2820D9623BF429}, // 1e284 + {0xA97C177947AD4095, 0xD732290FBACAF133}, // 1e285 + {0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0}, // 1e286 + {0x5C68F256BFFF5A74, 0xA81F301449EE8C70}, // 1e287 + {0x73832EEC6FFF3111, 0xD226FC195C6A2F8C}, // 1e288 + {0xC831FD53C5FF7EAB, 0x83585D8FD9C25DB7}, // 1e289 + {0xBA3E7CA8B77F5E55, 0xA42E74F3D032F525}, // 1e290 + {0x28CE1BD2E55F35EB, 0xCD3A1230C43FB26F}, // 1e291 + {0x7980D163CF5B81B3, 0x80444B5E7AA7CF85}, // 1e292 + {0xD7E105BCC332621F, 0xA0555E361951C366}, // 1e293 + {0x8DD9472BF3FEFAA7, 0xC86AB5C39FA63440}, // 1e294 + {0xB14F98F6F0FEB951, 0xFA856334878FC150}, // 1e295 + {0x6ED1BF9A569F33D3, 0x9C935E00D4B9D8D2}, // 1e296 + {0x0A862F80EC4700C8, 0xC3B8358109E84F07}, // 1e297 + {0xCD27BB612758C0FA, 0xF4A642E14C6262C8}, // 1e298 + {0x8038D51CB897789C, 0x98E7E9CCCFBD7DBD}, // 1e299 + {0xE0470A63E6BD56C3, 0xBF21E44003ACDD2C}, // 1e300 + {0x1858CCFCE06CAC74, 0xEEEA5D5004981478}, // 1e301 + {0x0F37801E0C43EBC8, 0x95527A5202DF0CCB}, // 1e302 + {0xD30560258F54E6BA, 0xBAA718E68396CFFD}, // 1e303 + {0x47C6B82EF32A2069, 0xE950DF20247C83FD}, // 1e304 + {0x4CDC331D57FA5441, 0x91D28B7416CDD27E}, // 1e305 + {0xE0133FE4ADF8E952, 0xB6472E511C81471D}, // 1e306 + {0x58180FDDD97723A6, 0xE3D8F9E563A198E5}, // 1e307 + {0x570F09EAA7EA7648, 0x8E679C2F5E44FF8F}, // 1e308 + {0x2CD2CC6551E513DA, 0xB201833B35D63F73}, // 1e309 + {0xF8077F7EA65E58D1, 0xDE81E40A034BCF4F}, // 1e310 + {0xFB04AFAF27FAF782, 0x8B112E86420F6191}, // 1e311 + {0x79C5DB9AF1F9B563, 0xADD57A27D29339F6}, // 1e312 + {0x18375281AE7822BC, 0xD94AD8B1C7380874}, // 1e313 + {0x8F2293910D0B15B5, 0x87CEC76F1C830548}, // 1e314 + {0xB2EB3875504DDB22, 0xA9C2794AE3A3C69A}, // 1e315 + {0x5FA60692A46151EB, 0xD433179D9C8CB841}, // 1e316 + {0xDBC7C41BA6BCD333, 0x849FEEC281D7F328}, // 1e317 + {0x12B9B522906C0800, 0xA5C7EA73224DEFF3}, // 1e318 + {0xD768226B34870A00, 0xCF39E50FEAE16BEF}, // 1e319 + {0xE6A1158300D46640, 0x81842F29F2CCE375}, // 1e320 + {0x60495AE3C1097FD0, 0xA1E53AF46F801C53}, // 1e321 + {0x385BB19CB14BDFC4, 0xCA5E89B18B602368}, // 1e322 + {0x46729E03DD9ED7B5, 0xFCF62C1DEE382C42}, // 1e323 + {0x6C07A2C26A8346D1, 0x9E19DB92B4E31BA9}, // 1e324 + {0xC7098B7305241885, 0xC5A05277621BE293}, // 1e325 + {0xB8CBEE4FC66D1EA7, 0xF70867153AA2DB38}, // 1e326 + {0x737F74F1DC043328, 0x9A65406D44A5C903}, // 1e327 + {0x505F522E53053FF2, 0xC0FE908895CF3B44}, // 1e328 + {0x647726B9E7C68FEF, 0xF13E34AABB430A15}, // 1e329 + {0x5ECA783430DC19F5, 0x96C6E0EAB509E64D}, // 1e330 + {0xB67D16413D132072, 0xBC789925624C5FE0}, // 1e331 + {0xE41C5BD18C57E88F, 0xEB96BF6EBADF77D8}, // 1e332 + {0x8E91B962F7B6F159, 0x933E37A534CBAAE7}, // 1e333 + {0x723627BBB5A4ADB0, 0xB80DC58E81FE95A1}, // 1e334 + {0xCEC3B1AAA30DD91C, 0xE61136F2227E3B09}, // 1e335 + {0x213A4F0AA5E8A7B1, 0x8FCAC257558EE4E6}, // 1e336 + {0xA988E2CD4F62D19D, 0xB3BD72ED2AF29E1F}, // 1e337 + {0x93EB1B80A33B8605, 0xE0ACCFA875AF45A7}, // 1e338 + {0xBC72F130660533C3, 0x8C6C01C9498D8B88}, // 1e339 + {0xEB8FAD7C7F8680B4, 0xAF87023B9BF0EE6A}, // 1e340 + {0xA67398DB9F6820E1, 0xDB68C2CA82ED2A05}, // 1e341 + {0x88083F8943A1148C, 0x892179BE91D43A43}, // 1e342 + {0x6A0A4F6B948959B0, 0xAB69D82E364948D4}, // 1e343 + {0x848CE34679ABB01C, 0xD6444E39C3DB9B09}, // 1e344 + {0xF2D80E0C0C0B4E11, 0x85EAB0E41A6940E5}, // 1e345 + {0x6F8E118F0F0E2195, 0xA7655D1D2103911F}, // 1e346 + {0x4B7195F2D2D1A9FB, 0xD13EB46469447567}, // 1e347 +} diff --git a/gnovm/stdlibs/strconv/example_test.gno b/gnovm/stdlibs/strconv/example_test.gno new file mode 100644 index 00000000000..428fde4e660 --- /dev/null +++ b/gnovm/stdlibs/strconv/example_test.gno @@ -0,0 +1,440 @@ +// Copyright 2015 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 strconv_test + +import ( + "fmt" + "log" + "strconv" +) + +func ExampleAppendBool() { + b := []byte("bool:") + b = strconv.AppendBool(b, true) + fmt.Println(string(b)) + + // Output: + // bool:true +} + +func ExampleAppendFloat() { + b32 := []byte("float32:") + b32 = strconv.AppendFloat(b32, 3.1415926535, 'E', -1, 32) + fmt.Println(string(b32)) + + b64 := []byte("float64:") + b64 = strconv.AppendFloat(b64, 3.1415926535, 'E', -1, 64) + fmt.Println(string(b64)) + + // Output: + // float32:3.1415927E+00 + // float64:3.1415926535E+00 +} + +func ExampleAppendInt() { + b10 := []byte("int (base 10):") + b10 = strconv.AppendInt(b10, -42, 10) + fmt.Println(string(b10)) + + b16 := []byte("int (base 16):") + b16 = strconv.AppendInt(b16, -42, 16) + fmt.Println(string(b16)) + + // Output: + // int (base 10):-42 + // int (base 16):-2a +} + +func ExampleAppendQuote() { + b := []byte("quote:") + b = strconv.AppendQuote(b, `"Fran & Freddie's Diner"`) + fmt.Println(string(b)) + + // Output: + // quote:"\"Fran & Freddie's Diner\"" +} + +func ExampleAppendQuoteRune() { + b := []byte("rune:") + b = strconv.AppendQuoteRune(b, '☺') + fmt.Println(string(b)) + + // Output: + // rune:'☺' +} + +func ExampleAppendQuoteRuneToASCII() { + b := []byte("rune (ascii):") + b = strconv.AppendQuoteRuneToASCII(b, '☺') + fmt.Println(string(b)) + + // Output: + // rune (ascii):'\u263a' +} + +func ExampleAppendQuoteToASCII() { + b := []byte("quote (ascii):") + b = strconv.AppendQuoteToASCII(b, `"Fran & Freddie's Diner"`) + fmt.Println(string(b)) + + // Output: + // quote (ascii):"\"Fran & Freddie's Diner\"" +} + +func ExampleAppendUint() { + b10 := []byte("uint (base 10):") + b10 = strconv.AppendUint(b10, 42, 10) + fmt.Println(string(b10)) + + b16 := []byte("uint (base 16):") + b16 = strconv.AppendUint(b16, 42, 16) + fmt.Println(string(b16)) + + // Output: + // uint (base 10):42 + // uint (base 16):2a +} + +func ExampleAtoi() { + v := "10" + if s, err := strconv.Atoi(v); err == nil { + fmt.Printf("%T, %v", s, s) + } + + // Output: + // int, 10 +} + +func ExampleCanBackquote() { + fmt.Println(strconv.CanBackquote("Fran & Freddie's Diner ☺")) + fmt.Println(strconv.CanBackquote("`can't backquote this`")) + + // Output: + // true + // false +} + +func ExampleFormatBool() { + v := true + s := strconv.FormatBool(v) + fmt.Printf("%T, %v\n", s, s) + + // Output: + // string, true +} + +func ExampleFormatFloat() { + v := 3.1415926535 + + s32 := strconv.FormatFloat(v, 'E', -1, 32) + fmt.Printf("%T, %v\n", s32, s32) + + s64 := strconv.FormatFloat(v, 'E', -1, 64) + fmt.Printf("%T, %v\n", s64, s64) + + // fmt.Println uses these arguments to print floats + fmt64 := strconv.FormatFloat(v, 'g', -1, 64) + fmt.Printf("%T, %v\n", fmt64, fmt64) + + // Output: + // string, 3.1415927E+00 + // string, 3.1415926535E+00 + // string, 3.1415926535 +} + +func ExampleFormatInt() { + v := int64(-42) + + s10 := strconv.FormatInt(v, 10) + fmt.Printf("%T, %v\n", s10, s10) + + s16 := strconv.FormatInt(v, 16) + fmt.Printf("%T, %v\n", s16, s16) + + // Output: + // string, -42 + // string, -2a +} + +func ExampleFormatUint() { + v := uint64(42) + + s10 := strconv.FormatUint(v, 10) + fmt.Printf("%T, %v\n", s10, s10) + + s16 := strconv.FormatUint(v, 16) + fmt.Printf("%T, %v\n", s16, s16) + + // Output: + // string, 42 + // string, 2a +} + +func ExampleIsGraphic() { + shamrock := strconv.IsGraphic('☘') + fmt.Println(shamrock) + + a := strconv.IsGraphic('a') + fmt.Println(a) + + bel := strconv.IsGraphic('\007') + fmt.Println(bel) + + // Output: + // true + // true + // false +} + +func ExampleIsPrint() { + c := strconv.IsPrint('\u263a') + fmt.Println(c) + + bel := strconv.IsPrint('\007') + fmt.Println(bel) + + // Output: + // true + // false +} + +func ExampleItoa() { + i := 10 + s := strconv.Itoa(i) + fmt.Printf("%T, %v\n", s, s) + + // Output: + // string, 10 +} + +func ExampleParseBool() { + v := "true" + if s, err := strconv.ParseBool(v); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // bool, true +} + +func ExampleParseFloat() { + v := "3.1415926535" + if s, err := strconv.ParseFloat(v, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat(v, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("NaN", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + // ParseFloat is case insensitive + if s, err := strconv.ParseFloat("nan", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("+Inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("-Inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("-0", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("+0", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // float64, 3.1415927410125732 + // float64, 3.1415926535 + // float64, NaN + // float64, NaN + // float64, +Inf + // float64, +Inf + // float64, -Inf + // float64, -0 + // float64, 0 +} + +func ExampleParseInt() { + v32 := "-354634382" + if s, err := strconv.ParseInt(v32, 10, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseInt(v32, 16, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + v64 := "-3546343826724305832" + if s, err := strconv.ParseInt(v64, 10, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseInt(v64, 16, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // int64, -354634382 + // int64, -3546343826724305832 +} + +func ExampleParseUint() { + v := "42" + if s, err := strconv.ParseUint(v, 10, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseUint(v, 10, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // uint64, 42 + // uint64, 42 +} + +func ExampleQuote() { + // This string literal contains a tab character. + s := strconv.Quote(`"Fran & Freddie's Diner ☺"`) + fmt.Println(s) + + // Output: + // "\"Fran & Freddie's Diner\t☺\"" +} + +func ExampleQuoteRune() { + s := strconv.QuoteRune('☺') + fmt.Println(s) + + // Output: + // '☺' +} + +func ExampleQuoteRuneToASCII() { + s := strconv.QuoteRuneToASCII('☺') + fmt.Println(s) + + // Output: + // '\u263a' +} + +func ExampleQuoteRuneToGraphic() { + s := strconv.QuoteRuneToGraphic('☺') + fmt.Println(s) + + s = strconv.QuoteRuneToGraphic('\u263a') + fmt.Println(s) + + s = strconv.QuoteRuneToGraphic('\u000a') + fmt.Println(s) + + s = strconv.QuoteRuneToGraphic(' ') // tab character + fmt.Println(s) + + // Output: + // '☺' + // '☺' + // '\n' + // '\t' +} + +func ExampleQuoteToASCII() { + // This string literal contains a tab character. + s := strconv.QuoteToASCII(`"Fran & Freddie's Diner ☺"`) + fmt.Println(s) + + // Output: + // "\"Fran & Freddie's Diner\t\u263a\"" +} + +func ExampleQuoteToGraphic() { + s := strconv.QuoteToGraphic("☺") + fmt.Println(s) + + // This string literal contains a tab character. + s = strconv.QuoteToGraphic("This is a \u263a \u000a") + fmt.Println(s) + + s = strconv.QuoteToGraphic(`" This is a ☺ \n "`) + fmt.Println(s) + + // Output: + // "☺" + // "This is a ☺\t\n" + // "\" This is a ☺ \\n \"" +} + +func ExampleQuotedPrefix() { + s, err := strconv.QuotedPrefix("not a quoted string") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.QuotedPrefix("\"double-quoted string\" with trailing text") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.QuotedPrefix("`or backquoted` with more trailing text") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.QuotedPrefix("'\u263a' is also okay") + fmt.Printf("%q, %v\n", s, err) + + // Output: + // "", invalid syntax + // "\"double-quoted string\"", + // "`or backquoted`", + // "'☺'", +} + +func ExampleUnquote() { + s, err := strconv.Unquote("You can't unquote a string without quotes") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("\"The string must be either double-quoted\"") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("`or backquoted.`") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("'\u263a'") // single character only allowed in single quotes + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("'\u2639\u2639'") + fmt.Printf("%q, %v\n", s, err) + + // Output: + // "", invalid syntax + // "The string must be either double-quoted", + // "or backquoted.", + // "☺", + // "", invalid syntax +} + +func ExampleUnquoteChar() { + v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"') + if err != nil { + log.Fatal(err) + } + + fmt.Println("value:", string(v)) + fmt.Println("multibyte:", mb) + fmt.Println("tail:", t) + + // Output: + // value: " + // multibyte: false + // tail: Fran & Freddie's Diner\" +} + +func ExampleNumError() { + str := "Not a number" + if _, err := strconv.ParseFloat(str, 64); err != nil { + e := err.(*strconv.NumError) + fmt.Println("Func:", e.Func) + fmt.Println("Num:", e.Num) + fmt.Println("Err:", e.Err) + fmt.Println(err) + } + + // Output: + // Func: ParseFloat + // Num: Not a number + // Err: invalid syntax + // strconv.ParseFloat: parsing "Not a number": invalid syntax +} diff --git a/gnovm/stdlibs/strconv/export_test.gno b/gnovm/stdlibs/strconv/export_test.gno new file mode 100644 index 00000000000..8c03a7ffb4f --- /dev/null +++ b/gnovm/stdlibs/strconv/export_test.gno @@ -0,0 +1,10 @@ +// Copyright 2017 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 strconv + +var ( + BitSizeError = bitSizeError + BaseError = baseError +) diff --git a/gnovm/stdlibs/strconv/fp_test.gno b/gnovm/stdlibs/strconv/fp_test.gno new file mode 100644 index 00000000000..76cc95663c4 --- /dev/null +++ b/gnovm/stdlibs/strconv/fp_test.gno @@ -0,0 +1,320 @@ +// 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 strconv_test + +import ( + "bufio" + "fmt" + "strconv" + "strings" + "testing" +) + +func pow2(i int) float64 { + switch { + case i < 0: + return 1 / pow2(-i) + case i == 0: + return 1 + case i == 1: + return 2 + } + return pow2(i/2) * pow2(i-i/2) +} + +// Wrapper around strconv.ParseFloat(x, 64). Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.ParseFloat. +func myatof64(s string) (f float64, ok bool) { + if mant, exp, ok := strings.Cut(s, "p"); ok { + n, err := strconv.ParseInt(mant, 10, 64) + if err != nil { + return 0, false + } + e, err1 := strconv.Atoi(exp) + if err1 != nil { + println("bad e", exp) + return 0, false + } + v := float64(n) + // We expect that v*pow2(e) fits in a float64, + // but pow2(e) by itself may not. Be careful. + if e <= -1000 { + v *= pow2(-1000) + e += 1000 + for e < 0 { + v /= 2 + e++ + } + return v, true + } + if e >= 1000 { + v *= pow2(1000) + e -= 1000 + for e > 0 { + v *= 2 + e-- + } + return v, true + } + return v * pow2(e), true + } + f1, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0, false + } + return f1, true +} + +// Wrapper around strconv.ParseFloat(x, 32). Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.ParseFloat. +func myatof32(s string) (f float32, ok bool) { + if mant, exp, ok := strings.Cut(s, "p"); ok { + n, err := strconv.Atoi(mant) + if err != nil { + println("bad n", mant) + return 0, false + } + e, err1 := strconv.Atoi(exp) + if err1 != nil { + println("bad p", exp) + return 0, false + } + return float32(float64(n) * pow2(e)), true + } + f64, err1 := strconv.ParseFloat(s, 32) + f1 := float32(f64) + if err1 != nil { + return 0, false + } + return f1, true +} + +// XXX: copied from go source src/strconv/testdata/testfp.txt +// to avoid using os.Open in our tests +const testfp = `# Floating-point conversion test cases. +# Empty lines and lines beginning with # are ignored. +# The rest have four fields per line: type, format, input, and output. +# The input is given either in decimal or binary scientific notation. +# The output is the string that should be produced by formatting the +# input with the given format. +# +# The formats are as in C's printf, except that %b means print +# binary scientific notation: NpE = N x 2^E. + +# TODO: +# Powers of 10. +# Powers of 2. +# %.20g versions. +# random sources +# random targets +# random targets ± half a ULP + +# Difficult boundary cases, derived from tables given in +# Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion +# ftp://ftp.ee.lbl.gov/testbase-report.ps.Z + +# Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP +float64 %b 5e+125 6653062250012735p+365 +float64 %b 69e+267 4705683757438170p+841 +float64 %b 999e-026 6798841691080350p-129 +float64 %b 7861e-034 8975675289889240p-153 +float64 %b 75569e-254 6091718967192243p-880 +float64 %b 928609e-261 7849264900213743p-900 +float64 %b 9210917e+080 8341110837370930p+236 +float64 %b 84863171e+114 4625202867375927p+353 +float64 %b 653777767e+273 5068902999763073p+884 +float64 %b 5232604057e-298 5741343011915040p-1010 +float64 %b 27235667517e-109 6707124626673586p-380 +float64 %b 653532977297e-123 7078246407265384p-422 +float64 %b 3142213164987e-294 8219991337640559p-988 +float64 %b 46202199371337e-072 5224462102115359p-246 +float64 %b 231010996856685e-073 5224462102115359p-247 +float64 %b 9324754620109615e+212 5539753864394442p+705 +float64 %b 78459735791271921e+049 8388176519442766p+166 +float64 %b 272104041512242479e+200 5554409530847367p+670 +float64 %b 6802601037806061975e+198 5554409530847367p+668 +float64 %b 20505426358836677347e-221 4524032052079546p-722 +float64 %b 836168422905420598437e-234 5070963299887562p-760 +float64 %b 4891559871276714924261e+222 6452687840519111p+757 + +# Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP +float64 %b 9e-265 8168427841980010p-930 +float64 %b 85e-037 6360455125664090p-169 +float64 %b 623e+100 6263531988747231p+289 +float64 %b 3571e+263 6234526311072170p+833 +float64 %b 81661e+153 6696636728760206p+472 +float64 %b 920657e-023 5975405561110124p-109 +float64 %b 4603285e-024 5975405561110124p-110 +float64 %b 87575437e-309 8452160731874668p-1053 +float64 %b 245540327e+122 4985336549131723p+381 +float64 %b 6138508175e+120 4985336549131723p+379 +float64 %b 83356057653e+193 5986732817132056p+625 +float64 %b 619534293513e+124 4798406992060657p+399 +float64 %b 2335141086879e+218 5419088166961646p+713 +float64 %b 36167929443327e-159 8135819834632444p-536 +float64 %b 609610927149051e-255 4576664294594737p-850 +float64 %b 3743626360493413e-165 6898586531774201p-549 +float64 %b 94080055902682397e-242 6273271706052298p-800 +float64 %b 899810892172646163e+283 7563892574477827p+947 +float64 %b 7120190517612959703e+120 5385467232557565p+409 +float64 %b 25188282901709339043e-252 5635662608542340p-825 +float64 %b 308984926168550152811e-052 5644774693823803p-157 +float64 %b 6372891218502368041059e+064 4616868614322430p+233 + +# Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP +float64 %.0e 8511030020275656p-342 9e-88 +float64 %.1e 5201988407066741p-824 4.6e-233 +float64 %.2e 6406892948269899p+237 1.41e+87 +float64 %.3e 8431154198732492p+72 3.981e+37 +float64 %.4e 6475049196144587p+99 4.1040e+45 +float64 %.5e 8274307542972842p+726 2.92084e+234 +float64 %.6e 5381065484265332p-456 2.891946e-122 +float64 %.7e 6761728585499734p-1057 4.3787718e-303 +float64 %.8e 7976538478610756p+376 1.22770163e+129 +float64 %.9e 5982403858958067p+377 1.841552452e+129 +float64 %.10e 5536995190630837p+93 5.4835744350e+43 +float64 %.11e 7225450889282194p+710 3.89190181146e+229 +float64 %.12e 7225450889282194p+709 1.945950905732e+229 +float64 %.13e 8703372741147379p+117 1.4460958381605e+51 +float64 %.14e 8944262675275217p-1001 4.17367747458531e-286 +float64 %.15e 7459803696087692p-707 1.107950772878888e-197 +float64 %.16e 6080469016670379p-381 1.2345501366327440e-99 +float64 %.17e 8385515147034757p+721 9.25031711960365024e+232 +float64 %.18e 7514216811389786p-828 4.198047150284889840e-234 +float64 %.19e 8397297803260511p-345 1.1716315319786511046e-88 +float64 %.20e 6733459239310543p+202 4.32810072844612493629e+76 +float64 %.21e 8091450587292794p-473 3.317710118160031081518e-127 + +# Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP +float64 %.0e 6567258882077402p+952 3e+302 +float64 %.1e 6712731423444934p+535 7.6e+176 +float64 %.2e 6712731423444934p+534 3.78e+176 +float64 %.3e 5298405411573037p-957 4.350e-273 +float64 %.4e 5137311167659507p-144 2.3037e-28 +float64 %.5e 6722280709661868p+363 1.26301e+125 +float64 %.6e 5344436398034927p-169 7.142211e-36 +float64 %.7e 8369123604277281p-853 1.3934574e-241 +float64 %.8e 8995822108487663p-780 1.41463449e-219 +float64 %.9e 8942832835564782p-383 4.539277920e-100 +float64 %.10e 8942832835564782p-384 2.2696389598e-100 +float64 %.11e 8942832835564782p-385 1.13481947988e-100 +float64 %.12e 6965949469487146p-249 7.700366561890e-60 +float64 %.13e 6965949469487146p-250 3.8501832809448e-60 +float64 %.14e 6965949469487146p-251 1.92509164047238e-60 +float64 %.15e 7487252720986826p+548 6.898586531774201e+180 +float64 %.16e 5592117679628511p+164 1.3076622631878654e+65 +float64 %.17e 8887055249355788p+665 1.36052020756121240e+216 +float64 %.18e 6994187472632449p+690 3.592810217475959676e+223 +float64 %.19e 8797576579012143p+588 8.9125197712484551899e+192 +float64 %.20e 7363326733505337p+272 5.58769757362301140950e+97 +float64 %.21e 8549497411294502p-448 1.176257830728540379990e-119 + +# Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP +# NOTE: The lines with exponent p-149 have been changed from the +# paper. Those entries originally read p-150 and had a mantissa +# twice as large (and even), but IEEE single-precision has no p-150: +# that's the start of the denormals. +float32 %b 5e-20 15474250p-88 +float32 %b 67e+14 12479722p+29 +float32 %b 985e+15 14333636p+36 +# float32 %b 7693e-42 10979816p-150 +float32 %b 7693e-42 5489908p-149 +float32 %b 55895e-16 12888509p-61 +# float32 %b 996622e-44 14224264p-150 +float32 %b 996622e-44 7112132p-149 +float32 %b 7038531e-32 11420669p-107 +# float32 %b 60419369e-46 8623340p-150 +float32 %b 60419369e-46 4311670p-149 +float32 %b 702990899e-20 16209866p-61 +# float32 %b 6930161142e-48 9891056p-150 +float32 %b 6930161142e-48 4945528p-149 +float32 %b 25933168707e+13 14395800p+54 +float32 %b 596428896559e+20 12333860p+82 + +# Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP +float32 %b 3e-23 9507380p-98 +float32 %b 57e+18 12960300p+42 +float32 %b 789e-35 10739312p-130 +float32 %b 2539e-18 11990089p-72 +float32 %b 76173e+28 9845130p+86 +float32 %b 887745e-11 9760860p-40 +float32 %b 5382571e-37 11447463p-124 +float32 %b 82381273e-35 8554961p-113 +float32 %b 750486563e-38 9975678p-120 +float32 %b 3752432815e-39 9975678p-121 +float32 %b 75224575729e-45 13105970p-137 +float32 %b 459926601011e+15 12466336p+65 + +# Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP +float32 %.0e 12676506p-102 2e-24 +float32 %.1e 12676506p-103 1.2e-24 +float32 %.2e 15445013p+86 1.19e+33 +float32 %.3e 13734123p-138 3.941e-35 +float32 %.4e 12428269p-130 9.1308e-33 +float32 %.5e 15334037p-146 1.71900e-37 +float32 %.6e 11518287p-41 5.237910e-06 +float32 %.7e 12584953p-145 2.8216440e-37 +float32 %.8e 15961084p-125 3.75243281e-31 +float32 %.9e 14915817p-146 1.672120916e-37 +float32 %.10e 10845484p-102 2.1388945814e-24 +float32 %.11e 16431059p-61 7.12583594561e-12 + +# Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP +float32 %.0e 16093626p+69 1e+28 +float32 %.1e 9983778p+25 3.4e+14 +float32 %.2e 12745034p+104 2.59e+38 +float32 %.3e 12706553p+72 6.001e+28 +float32 %.4e 11005028p+45 3.8721e+20 +float32 %.5e 15059547p+71 3.55584e+28 +float32 %.6e 16015691p-99 2.526831e-23 +float32 %.7e 8667859p+56 6.2458507e+23 +float32 %.8e 14855922p-82 3.07213267e-18 +float32 %.9e 14855922p-83 1.536066333e-18 +float32 %.10e 10144164p-110 7.8147796834e-27 +float32 %.11e 13248074p+95 5.24810279937e+35 +` + +func TestFp(t *testing.T) { + s := bufio.NewScanner(strings.NewReader(testfp)) + + for lineno := 1; s.Scan(); lineno++ { + line := s.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + a := strings.Split(line, " ") + if len(a) != 4 { + t.Error("testdata/testfp.txt:", lineno, ": wrong field count") + continue + } + var s string + var v float64 + switch a[0] { + case "float64": + var ok bool + v, ok = myatof64(a[2]) + if !ok { + t.Error("testdata/testfp.txt:", lineno, ": cannot atof64 ", a[2]) + continue + } + s = fmt.Sprintf(a[1], v) + case "float32": + v1, ok := myatof32(a[2]) + if !ok { + t.Error("testdata/testfp.txt:", lineno, ": cannot atof32 ", a[2]) + continue + } + s = fmt.Sprintf(a[1], v1) + v = float64(v1) + } + if s != a[3] { + t.Error("testdata/testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ", + "want ", a[3], " got ", s) + } + } + if s.Err() != nil { + t.Fatal("testfp: read testdata/testfp.txt: ", s.Err()) + } +} diff --git a/gnovm/stdlibs/strconv/ftoa.gno b/gnovm/stdlibs/strconv/ftoa.gno new file mode 100644 index 00000000000..fcbf4df13b6 --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoa.gno @@ -0,0 +1,584 @@ +// 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. + +// Binary to decimal floating point conversion. +// Algorithm: +// 1) store mantissa in multiprecision decimal +// 2) shift decimal by exponent +// 3) read digits out & format + +package strconv + +import "math" + +// TODO: move elsewhere? +type floatInfo struct { + mantbits uint + expbits uint + bias int +} + +var float32info = floatInfo{23, 8, -127} +var float64info = floatInfo{52, 11, -1023} + +// FormatFloat converts the floating-point number f to a string, +// according to the format fmt and precision prec. It rounds the +// result assuming that the original was obtained from a floating-point +// value of bitSize bits (32 for float32, 64 for float64). +// +// The format fmt is one of +// 'b' (-ddddp±ddd, a binary exponent), +// 'e' (-d.dddde±dd, a decimal exponent), +// 'E' (-d.ddddE±dd, a decimal exponent), +// 'f' (-ddd.dddd, no exponent), +// 'g' ('e' for large exponents, 'f' otherwise), +// 'G' ('E' for large exponents, 'f' otherwise), +// 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or +// 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent). +// +// The precision prec controls the number of digits (excluding the exponent) +// printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats. +// For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point. +// For 'g' and 'G' it is the maximum number of significant digits (trailing +// zeros are removed). +// The special precision -1 uses the smallest number of digits +// necessary such that ParseFloat will return f exactly. +func FormatFloat(f float64, fmt byte, prec, bitSize int) string { + return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize)) +} + +// AppendFloat appends the string form of the floating-point number f, +// as generated by FormatFloat, to dst and returns the extended buffer. +func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte { + return genericFtoa(dst, f, fmt, prec, bitSize) +} + +func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte { + var bits uint64 + var flt *floatInfo + switch bitSize { + case 32: + bits = uint64(math.Float32bits(float32(val))) + flt = &float32info + case 64: + bits = math.Float64bits(val) + flt = &float64info + default: + panic("strconv: illegal AppendFloat/FormatFloat bitSize") + } + + neg := bits>>(flt.expbits+flt.mantbits) != 0 + exp := int(bits>>flt.mantbits) & (1< digs.nd && digs.nd >= digs.dp { + eprec = digs.nd + } + // %e is used if the exponent from the conversion + // is less than -4 or greater than or equal to the precision. + // if precision was the shortest possible, use precision 6 for this decision. + if shortest { + eprec = 6 + } + exp := digs.dp - 1 + if exp < -4 || exp >= eprec { + if prec > digs.nd { + prec = digs.nd + } + return fmtE(dst, neg, digs, prec-1, fmt+'e'-'g') + } + if prec > digs.dp { + prec = digs.nd + } + return fmtF(dst, neg, digs, max(prec-digs.dp, 0)) + } + + // unknown format + return append(dst, '%', fmt) +} + +// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits +// that will let the original floating point value be precisely reconstructed. +func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { + // If mantissa is zero, the number is zero; stop now. + if mant == 0 { + d.nd = 0 + return + } + + // Compute upper and lower such that any decimal number + // between upper and lower (possibly inclusive) + // will round to the original floating point number. + + // We may see at once that the number is already shortest. + // + // Suppose d is not denormal, so that 2^exp <= d < 10^dp. + // The closest shorter number is at least 10^(dp-nd) away. + // The lower/upper bounds computed below are at distance + // at most 2^(exp-mantbits). + // + // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), + // or equivalently log2(10)*(dp-nd) > exp-mantbits. + // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). + minexp := flt.bias + 1 // minimum possible exponent + if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { + // The number is already shortest. + return + } + + // d = mant << (exp - mantbits) + // Next highest floating point number is mant+1 << exp-mantbits. + // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. + upper := new(decimal) + upper.Assign(mant*2 + 1) + upper.Shift(exp - int(flt.mantbits) - 1) + + // d = mant << (exp - mantbits) + // Next lowest floating point number is mant-1 << exp-mantbits, + // unless mant-1 drops the significant bit and exp is not the minimum exp, + // in which case the next lowest is mant*2-1 << exp-mantbits-1. + // Either way, call it mantlo << explo-mantbits. + // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. + var mantlo uint64 + var explo int + if mant > 1<= d.nd { + break + } + li := ui - upper.dp + lower.dp + l := byte('0') // lower digit + if li >= 0 && li < lower.nd { + l = lower.d[li] + } + m := byte('0') // middle digit + if mi >= 0 { + m = d.d[mi] + } + u := byte('0') // upper digit + if ui < upper.nd { + u = upper.d[ui] + } + + // Okay to round down (truncate) if lower has a different digit + // or if lower is inclusive and is exactly the result of rounding + // down (i.e., and we have reached the final digit of lower). + okdown := l != m || inclusive && li+1 == lower.nd + + switch { + case upperdelta == 0 && m+1 < u: + // Example: + // m = 12345xxx + // u = 12347xxx + upperdelta = 2 + case upperdelta == 0 && m != u: + // Example: + // m = 12345xxx + // u = 12346xxx + upperdelta = 1 + case upperdelta == 1 && (m != '9' || u != '0'): + // Example: + // m = 1234598x + // u = 1234600x + upperdelta = 2 + } + // Okay to round up if upper has a different digit and either upper + // is inclusive or upper is bigger than the result of rounding up. + okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd) + + // If it's okay to do either, then round to the nearest one. + // If it's okay to do only one, do it. + switch { + case okdown && okup: + d.Round(mi + 1) + return + case okdown: + d.RoundDown(mi + 1) + return + case okup: + d.RoundUp(mi + 1) + return + } + } +} + +type decimalSlice struct { + d []byte + nd, dp int +} + +// %e: -d.ddddde±dd +func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte { + // sign + if neg { + dst = append(dst, '-') + } + + // first digit + ch := byte('0') + if d.nd != 0 { + ch = d.d[0] + } + dst = append(dst, ch) + + // .moredigits + if prec > 0 { + dst = append(dst, '.') + i := 1 + m := min(d.nd, prec+1) + if i < m { + dst = append(dst, d.d[i:m]...) + i = m + } + for ; i <= prec; i++ { + dst = append(dst, '0') + } + } + + // e± + dst = append(dst, fmt) + exp := d.dp - 1 + if d.nd == 0 { // special case: 0 has exponent 0 + exp = 0 + } + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd + switch { + case exp < 10: + dst = append(dst, '0', byte(exp)+'0') + case exp < 100: + dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') + default: + dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0') + } + + return dst +} + +// %f: -ddddddd.ddddd +func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte { + // sign + if neg { + dst = append(dst, '-') + } + + // integer, padded with zeros as needed. + if d.dp > 0 { + m := min(d.nd, d.dp) + dst = append(dst, d.d[:m]...) + for ; m < d.dp; m++ { + dst = append(dst, '0') + } + } else { + dst = append(dst, '0') + } + + // fraction + if prec > 0 { + dst = append(dst, '.') + for i := 0; i < prec; i++ { + ch := byte('0') + if j := d.dp + i; 0 <= j && j < d.nd { + ch = d.d[j] + } + dst = append(dst, ch) + } + } + + return dst +} + +// %b: -ddddddddp±ddd +func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { + // sign + if neg { + dst = append(dst, '-') + } + + // mantissa + dst, _ = formatBits(dst, mant, 10, false, true) + + // p + dst = append(dst, 'p') + + // ±exponent + exp -= int(flt.mantbits) + if exp >= 0 { + dst = append(dst, '+') + } + dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true) + + return dst +} + +// %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit) +func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { + if mant == 0 { + exp = 0 + } + + // Shift digits so leading 1 (if any) is at bit 1<<60. + mant <<= 60 - flt.mantbits + for mant != 0 && mant&(1<<60) == 0 { + mant <<= 1 + exp-- + } + + // Round if requested. + if prec >= 0 && prec < 15 { + shift := uint(prec * 4) + extra := (mant << shift) & (1<<60 - 1) + mant >>= 60 - shift + if extra|(mant&1) > 1<<59 { + mant++ + } + mant <<= 60 - shift + if mant&(1<<61) != 0 { + // Wrapped around. + mant >>= 1 + exp++ + } + } + + hex := lowerhex + if fmt == 'X' { + hex = upperhex + } + + // sign, 0x, leading digit + if neg { + dst = append(dst, '-') + } + dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1)) + + // .fraction + mant <<= 4 // remove leading 0 or 1 + if prec < 0 && mant != 0 { + dst = append(dst, '.') + for mant != 0 { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } else if prec > 0 { + dst = append(dst, '.') + for i := 0; i < prec; i++ { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } + + // p± + ch := byte('P') + if fmt == lower(fmt) { + ch = 'p' + } + dst = append(dst, ch) + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd or dddd + switch { + case exp < 100: + dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') + case exp < 1000: + dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0') + default: + dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0') + } + + return dst +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/gnovm/stdlibs/strconv/ftoa_test.gno b/gnovm/stdlibs/strconv/ftoa_test.gno new file mode 100644 index 00000000000..df1cc733827 --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoa_test.gno @@ -0,0 +1,323 @@ +// 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 strconv + +import ( + "math" + "math/rand" + "testing" +) + +type ftoaTest struct { + f float64 + fmt byte + prec int + s string +} + +func fdiv(a, b float64) float64 { return a / b } + +const ( + below1e23 = 99999999999999974834176 + above1e23 = 100000000000000008388608 +) + +var ftoatests = []ftoaTest{ + {1, 'e', 5, "1.00000e+00"}, + {1, 'f', 5, "1.00000"}, + {1, 'g', 5, "1"}, + {1, 'g', -1, "1"}, + {1, 'x', -1, "0x1p+00"}, + {1, 'x', 5, "0x1.00000p+00"}, + {20, 'g', -1, "20"}, + {20, 'x', -1, "0x1.4p+04"}, + {1234567.8, 'g', -1, "1.2345678e+06"}, + {1234567.8, 'x', -1, "0x1.2d687cccccccdp+20"}, + {200000, 'g', -1, "200000"}, + {200000, 'x', -1, "0x1.86ap+17"}, + {200000, 'X', -1, "0X1.86AP+17"}, + {2000000, 'g', -1, "2e+06"}, + {1e10, 'g', -1, "1e+10"}, + + // g conversion and zero suppression + {400, 'g', 2, "4e+02"}, + {40, 'g', 2, "40"}, + {4, 'g', 2, "4"}, + {.4, 'g', 2, "0.4"}, + {.04, 'g', 2, "0.04"}, + {.004, 'g', 2, "0.004"}, + {.0004, 'g', 2, "0.0004"}, + {.00004, 'g', 2, "4e-05"}, + {.000004, 'g', 2, "4e-06"}, + + {0, 'e', 5, "0.00000e+00"}, + {0, 'f', 5, "0.00000"}, + {0, 'g', 5, "0"}, + {0, 'g', -1, "0"}, + {0, 'x', 5, "0x0.00000p+00"}, + + {-1, 'e', 5, "-1.00000e+00"}, + {-1, 'f', 5, "-1.00000"}, + {-1, 'g', 5, "-1"}, + {-1, 'g', -1, "-1"}, + + {12, 'e', 5, "1.20000e+01"}, + {12, 'f', 5, "12.00000"}, + {12, 'g', 5, "12"}, + {12, 'g', -1, "12"}, + + {123456700, 'e', 5, "1.23457e+08"}, + {123456700, 'f', 5, "123456700.00000"}, + {123456700, 'g', 5, "1.2346e+08"}, + {123456700, 'g', -1, "1.234567e+08"}, + + {1.2345e6, 'e', 5, "1.23450e+06"}, + {1.2345e6, 'f', 5, "1234500.00000"}, + {1.2345e6, 'g', 5, "1.2345e+06"}, + + // Round to even + {1.2345e6, 'e', 3, "1.234e+06"}, + {1.2355e6, 'e', 3, "1.236e+06"}, + {1.2345, 'f', 3, "1.234"}, + {1.2355, 'f', 3, "1.236"}, + {1234567890123456.5, 'e', 15, "1.234567890123456e+15"}, + {1234567890123457.5, 'e', 15, "1.234567890123458e+15"}, + {108678236358137.625, 'g', -1, "1.0867823635813762e+14"}, + + {1e23, 'e', 17, "9.99999999999999916e+22"}, + {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, + {1e23, 'g', 17, "9.9999999999999992e+22"}, + + {1e23, 'e', -1, "1e+23"}, + {1e23, 'f', -1, "100000000000000000000000"}, + {1e23, 'g', -1, "1e+23"}, + + {below1e23, 'e', 17, "9.99999999999999748e+22"}, + {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, + {below1e23, 'g', 17, "9.9999999999999975e+22"}, + + {below1e23, 'e', -1, "9.999999999999997e+22"}, + {below1e23, 'f', -1, "99999999999999970000000"}, + {below1e23, 'g', -1, "9.999999999999997e+22"}, + + {above1e23, 'e', 17, "1.00000000000000008e+23"}, + {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, + {above1e23, 'g', 17, "1.0000000000000001e+23"}, + + {above1e23, 'e', -1, "1.0000000000000001e+23"}, + {above1e23, 'f', -1, "100000000000000010000000"}, + {above1e23, 'g', -1, "1.0000000000000001e+23"}, + + {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, // avoid constant arithmetic + {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic + + {32, 'g', -1, "32"}, + {32, 'g', 0, "3e+01"}, + + {100, 'x', -1, "0x1.9p+06"}, + {100, 'y', -1, "%y"}, + + {math.NaN(), 'g', -1, "NaN"}, + {-math.NaN(), 'g', -1, "NaN"}, + {math.Inf(0), 'g', -1, "+Inf"}, + {math.Inf(-1), 'g', -1, "-Inf"}, + {-math.Inf(0), 'g', -1, "-Inf"}, + + {-1, 'b', -1, "-4503599627370496p-52"}, + + // fixed bugs + {0.9, 'f', 1, "0.9"}, + {0.09, 'f', 1, "0.1"}, + {0.0999, 'f', 1, "0.1"}, + {0.05, 'f', 1, "0.1"}, + {0.05, 'f', 0, "0"}, + {0.5, 'f', 1, "0.5"}, + {0.5, 'f', 0, "0"}, + {1.5, 'f', 0, "2"}, + + // https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, + // https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, + + // Issue 2625. + {383260575764816448, 'f', 0, "383260575764816448"}, + {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, + + // Issue 29491. + {498484681984085570, 'f', -1, "498484681984085570"}, + {-5.8339553793802237e+23, 'g', -1, "-5.8339553793802237e+23"}, + + // Issue 52187 + {123.45, '?', 0, "%?"}, + {123.45, '?', 1, "%?"}, + {123.45, '?', -1, "%?"}, + + // rounding + {2.275555555555555, 'x', -1, "0x1.23456789abcdep+01"}, + {2.275555555555555, 'x', 0, "0x1p+01"}, + {2.275555555555555, 'x', 2, "0x1.23p+01"}, + {2.275555555555555, 'x', 16, "0x1.23456789abcde000p+01"}, + {2.275555555555555, 'x', 21, "0x1.23456789abcde00000000p+01"}, + {2.2755555510520935, 'x', -1, "0x1.2345678p+01"}, + {2.2755555510520935, 'x', 6, "0x1.234568p+01"}, + {2.275555431842804, 'x', -1, "0x1.2345668p+01"}, + {2.275555431842804, 'x', 6, "0x1.234566p+01"}, + {3.999969482421875, 'x', -1, "0x1.ffffp+01"}, + {3.999969482421875, 'x', 4, "0x1.ffffp+01"}, + {3.999969482421875, 'x', 3, "0x1.000p+02"}, + {3.999969482421875, 'x', 2, "0x1.00p+02"}, + {3.999969482421875, 'x', 1, "0x1.0p+02"}, + {3.999969482421875, 'x', 0, "0x1p+02"}, +} + +func TestFtoa(t *testing.T) { + for i := 0; i < len(ftoatests); i++ { + test := &ftoatests[i] + s := FormatFloat(test.f, test.fmt, test.prec, 64) + if s != test.s { + t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 64) + if string(x) != "abc"+test.s { + t.Error("AppendFloat testN=64", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x)) + } + if float64(float32(test.f)) == test.f && test.fmt != 'b' { + s := FormatFloat(test.f, test.fmt, test.prec, 32) + if s != test.s { + t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 32) + if string(x) != "abc"+test.s { + t.Error("AppendFloat testN=32", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x)) + } + } + } +} + +func TestFtoaPowersOfTwo(t *testing.T) { + for exp := -2048; exp <= 2048; exp++ { + f := math.Ldexp(1, exp) + if !math.IsInf(f, 0) { + s := FormatFloat(f, 'e', -1, 64) + if x, _ := ParseFloat(s, 64); x != f { + t.Errorf("failed roundtrip %v => %s => %v", f, s, x) + } + } + f32 := float32(f) + if !math.IsInf(float64(f32), 0) { + s := FormatFloat(float64(f32), 'e', -1, 32) + if x, _ := ParseFloat(s, 32); float32(x) != f32 { + t.Errorf("failed roundtrip %v => %s => %v", f32, s, float32(x)) + } + } + } +} + +func TestFtoaRandom(t *testing.T) { + N := int(1e4) + if testing.Short() { + N = 100 + } + t.Logf("testing %d random numbers with fast and slow FormatFloat", N) + for i := 0; i < N; i++ { + bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32()) + x := math.Float64frombits(bits) + + shortFast := FormatFloat(x, 'g', -1, 64) + SetOptimize(false) + shortSlow := FormatFloat(x, 'g', -1, 64) + SetOptimize(true) + if shortSlow != shortFast { + t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow) + } + + prec := rand.IntN(12) + 5 + shortFast = FormatFloat(x, 'e', prec, 64) + SetOptimize(false) + shortSlow = FormatFloat(x, 'e', prec, 64) + SetOptimize(true) + if shortSlow != shortFast { + t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow) + } + } +} + +func TestFormatFloatInvalidBitSize(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("expected panic due to invalid bitSize") + } + }() + _ = FormatFloat(3.14, 'g', -1, 100) +} + +var ftoaBenches = []struct { + name string + float float64 + fmt byte + prec int + bitSize int +}{ + {"Decimal", 33909, 'g', -1, 64}, + {"Float", 339.7784, 'g', -1, 64}, + {"Exp", -5.09e75, 'g', -1, 64}, + {"NegExp", -5.11e-95, 'g', -1, 64}, + {"LongExp", 1.234567890123456e-78, 'g', -1, 64}, + + {"Big", 123456789123456789123456789, 'g', -1, 64}, + {"BinaryExp", -1, 'b', -1, 64}, + + {"32Integer", 33909, 'g', -1, 32}, + {"32ExactFraction", 3.375, 'g', -1, 32}, + {"32Point", 339.7784, 'g', -1, 32}, + {"32Exp", -5.09e25, 'g', -1, 32}, + {"32NegExp", -5.11e-25, 'g', -1, 32}, + {"32Shortest", 1.234567e-8, 'g', -1, 32}, + {"32Fixed8Hard", math.Ldexp(15961084, -125), 'e', 8, 32}, + {"32Fixed9Hard", math.Ldexp(14855922, -83), 'e', 9, 32}, + + {"64Fixed1", 123456, 'e', 3, 64}, + {"64Fixed2", 123.456, 'e', 3, 64}, + {"64Fixed3", 1.23456e+78, 'e', 3, 64}, + {"64Fixed4", 1.23456e-78, 'e', 3, 64}, + {"64Fixed12", 1.23456e-78, 'e', 12, 64}, + {"64Fixed16", 1.23456e-78, 'e', 16, 64}, + // From testdata/testfp.txt + {"64Fixed12Hard", math.Ldexp(6965949469487146, -249), 'e', 12, 64}, + {"64Fixed17Hard", math.Ldexp(8887055249355788, 665), 'e', 17, 64}, + {"64Fixed18Hard", math.Ldexp(6994187472632449, 690), 'e', 18, 64}, + + // Trigger slow path (see issue #15672). + // The shortest is: 8.034137530808823e+43 + {"Slowpath64", 8.03413753080882349e+43, 'e', -1, 64}, + // This denormal is pathological because the lower/upper + // halfways to neighboring floats are: + // 622666234635.321003e-320 ~= 622666234635.321e-320 + // 622666234635.321497e-320 ~= 622666234635.3215e-320 + // making it hard to find the 3rd digit + {"SlowpathDenormal64", 622666234635.3213e-320, 'e', -1, 64}, +} + +func BenchmarkFormatFloat(b *testing.B) { + for _, c := range ftoaBenches { + b.Run(c.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + FormatFloat(c.float, c.fmt, c.prec, c.bitSize) + } + }) + } +} + +func BenchmarkAppendFloat(b *testing.B) { + dst := make([]byte, 30) + for _, c := range ftoaBenches { + b.Run(c.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + AppendFloat(dst[:0], c.float, c.fmt, c.prec, c.bitSize) + } + }) + } +} diff --git a/gnovm/stdlibs/strconv/ftoaryu.gno b/gnovm/stdlibs/strconv/ftoaryu.gno new file mode 100644 index 00000000000..2e7bf71df0b --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoaryu.gno @@ -0,0 +1,569 @@ +// Copyright 2021 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 strconv + +import ( + "math/bits" +) + +// binary to decimal conversion using the Ryū algorithm. +// +// See Ulf Adams, "Ryū: Fast Float-to-String Conversion" (doi:10.1145/3192366.3192369) +// +// Fixed precision formatting is a variant of the original paper's +// algorithm, where a single multiplication by 10^k is required, +// sharing the same rounding guarantees. + +// ryuFtoaFixed32 formats mant*(2^exp) with prec decimal digits. +func ryuFtoaFixed32(d *decimalSlice, mant uint32, exp int, prec int) { + if prec < 0 { + panic("ryuFtoaFixed32 called with negative prec") + } + if prec > 9 { + panic("ryuFtoaFixed32 called with prec > 9") + } + // Zero input. + if mant == 0 { + d.nd, d.dp = 0, 0 + return + } + // Renormalize to a 25-bit mantissa. + e2 := exp + if b := bits.Len32(mant); b < 25 { + mant <<= uint(25 - b) + e2 += b - 25 + } + // Choose an exponent such that rounded mant*(2^e2)*(10^q) has + // at least prec decimal digits, i.e + // mant*(2^e2)*(10^q) >= 10^(prec-1) + // Because mant >= 2^24, it is enough to choose: + // 2^(e2+24) >= 10^(-q+prec-1) + // or q = -mulByLog2Log10(e2+24) + prec - 1 + q := -mulByLog2Log10(e2+24) + prec - 1 + + // Now compute mant*(2^e2)*(10^q). + // Is it an exact computation? + // Only small positive powers of 10 are exact (5^28 has 66 bits). + exact := q <= 27 && q >= 0 + + di, dexp2, d0 := mult64bitPow10(mant, e2, q) + if dexp2 >= 0 { + panic("not enough significant bits after mult64bitPow10") + } + // As a special case, computation might still be exact, if exponent + // was negative and if it amounts to computing an exact division. + // In that case, we ignore all lower bits. + // Note that division by 10^11 cannot be exact as 5^11 has 26 bits. + if q < 0 && q >= -10 && divisibleByPower5(uint64(mant), -q) { + exact = true + d0 = true + } + // Remove extra lower bits and keep rounding info. + extra := uint(-dexp2) + extraMask := uint32(1<>extra, di&extraMask + roundUp := false + if exact { + // If we computed an exact product, d + 1/2 + // should round to d+1 if 'd' is odd. + roundUp = dfrac > 1<<(extra-1) || + (dfrac == 1<<(extra-1) && !d0) || + (dfrac == 1<<(extra-1) && d0 && di&1 == 1) + } else { + // otherwise, d+1/2 always rounds up because + // we truncated below. + roundUp = dfrac>>(extra-1) == 1 + } + if dfrac != 0 { + d0 = false + } + // Proceed to the requested number of digits + formatDecimal(d, uint64(di), !d0, roundUp, prec) + // Adjust exponent + d.dp -= q +} + +// ryuFtoaFixed64 formats mant*(2^exp) with prec decimal digits. +func ryuFtoaFixed64(d *decimalSlice, mant uint64, exp int, prec int) { + if prec > 18 { + panic("ryuFtoaFixed64 called with prec > 18") + } + // Zero input. + if mant == 0 { + d.nd, d.dp = 0, 0 + return + } + // Renormalize to a 55-bit mantissa. + e2 := exp + if b := bits.Len64(mant); b < 55 { + mant = mant << uint(55-b) + e2 += b - 55 + } + // Choose an exponent such that rounded mant*(2^e2)*(10^q) has + // at least prec decimal digits, i.e + // mant*(2^e2)*(10^q) >= 10^(prec-1) + // Because mant >= 2^54, it is enough to choose: + // 2^(e2+54) >= 10^(-q+prec-1) + // or q = -mulByLog2Log10(e2+54) + prec - 1 + // + // The minimal required exponent is -mulByLog2Log10(1025)+18 = -291 + // The maximal required exponent is mulByLog2Log10(1074)+18 = 342 + q := -mulByLog2Log10(e2+54) + prec - 1 + + // Now compute mant*(2^e2)*(10^q). + // Is it an exact computation? + // Only small positive powers of 10 are exact (5^55 has 128 bits). + exact := q <= 55 && q >= 0 + + di, dexp2, d0 := mult128bitPow10(mant, e2, q) + if dexp2 >= 0 { + panic("not enough significant bits after mult128bitPow10") + } + // As a special case, computation might still be exact, if exponent + // was negative and if it amounts to computing an exact division. + // In that case, we ignore all lower bits. + // Note that division by 10^23 cannot be exact as 5^23 has 54 bits. + if q < 0 && q >= -22 && divisibleByPower5(mant, -q) { + exact = true + d0 = true + } + // Remove extra lower bits and keep rounding info. + extra := uint(-dexp2) + extraMask := uint64(1<>extra, di&extraMask + roundUp := false + if exact { + // If we computed an exact product, d + 1/2 + // should round to d+1 if 'd' is odd. + roundUp = dfrac > 1<<(extra-1) || + (dfrac == 1<<(extra-1) && !d0) || + (dfrac == 1<<(extra-1) && d0 && di&1 == 1) + } else { + // otherwise, d+1/2 always rounds up because + // we truncated below. + roundUp = dfrac>>(extra-1) == 1 + } + if dfrac != 0 { + d0 = false + } + // Proceed to the requested number of digits + formatDecimal(d, di, !d0, roundUp, prec) + // Adjust exponent + d.dp -= q +} + +var uint64pow10 = [...]uint64{ + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, +} + +// formatDecimal fills d with at most prec decimal digits +// of mantissa m. The boolean trunc indicates whether m +// is truncated compared to the original number being formatted. +func formatDecimal(d *decimalSlice, m uint64, trunc bool, roundUp bool, prec int) { + max := uint64pow10[prec] + trimmed := 0 + for m >= max { + a, b := m/10, m%10 + m = a + trimmed++ + if b > 5 { + roundUp = true + } else if b < 5 { + roundUp = false + } else { // b == 5 + // round up if there are trailing digits, + // or if the new value of m is odd (round-to-even convention) + roundUp = trunc || m&1 == 1 + } + if b != 0 { + trunc = true + } + } + if roundUp { + m++ + } + if m >= max { + // Happens if di was originally 99999....xx + m /= 10 + trimmed++ + } + // render digits (similar to formatBits) + n := uint(prec) + d.nd = prec + v := m + for v >= 100 { + var v1, v2 uint64 + if v>>32 == 0 { + v1, v2 = uint64(uint32(v)/100), uint64(uint32(v)%100) + } else { + v1, v2 = v/100, v%100 + } + n -= 2 + d.d[n+1] = smallsString[2*v2+1] + d.d[n+0] = smallsString[2*v2+0] + v = v1 + } + if v > 0 { + n-- + d.d[n] = smallsString[2*v+1] + } + if v >= 10 { + n-- + d.d[n] = smallsString[2*v] + } + for d.d[d.nd-1] == '0' { + d.nd-- + trimmed++ + } + d.dp = d.nd + trimmed +} + +// ryuFtoaShortest formats mant*2^exp with prec decimal digits. +func ryuFtoaShortest(d *decimalSlice, mant uint64, exp int, flt *floatInfo) { + if mant == 0 { + d.nd, d.dp = 0, 0 + return + } + // If input is an exact integer with fewer bits than the mantissa, + // the previous and next integer are not admissible representations. + if exp <= 0 && bits.TrailingZeros64(mant) >= -exp { + mant >>= uint(-exp) + ryuDigits(d, mant, mant, mant, true, false) + return + } + ml, mc, mu, e2 := computeBounds(mant, exp, flt) + if e2 == 0 { + ryuDigits(d, ml, mc, mu, true, false) + return + } + // Find 10^q *larger* than 2^-e2 + q := mulByLog2Log10(-e2) + 1 + + // We are going to multiply by 10^q using 128-bit arithmetic. + // The exponent is the same for all 3 numbers. + var dl, dc, du uint64 + var dl0, dc0, du0 bool + if flt == &float32info { + var dl32, dc32, du32 uint32 + dl32, _, dl0 = mult64bitPow10(uint32(ml), e2, q) + dc32, _, dc0 = mult64bitPow10(uint32(mc), e2, q) + du32, e2, du0 = mult64bitPow10(uint32(mu), e2, q) + dl, dc, du = uint64(dl32), uint64(dc32), uint64(du32) + } else { + dl, _, dl0 = mult128bitPow10(ml, e2, q) + dc, _, dc0 = mult128bitPow10(mc, e2, q) + du, e2, du0 = mult128bitPow10(mu, e2, q) + } + if e2 >= 0 { + panic("not enough significant bits after mult128bitPow10") + } + // Is it an exact computation? + if q > 55 { + // Large positive powers of ten are not exact + dl0, dc0, du0 = false, false, false + } + if q < 0 && q >= -24 { + // Division by a power of ten may be exact. + // (note that 5^25 is a 59-bit number so division by 5^25 is never exact). + if divisibleByPower5(ml, -q) { + dl0 = true + } + if divisibleByPower5(mc, -q) { + dc0 = true + } + if divisibleByPower5(mu, -q) { + du0 = true + } + } + // Express the results (dl, dc, du)*2^e2 as integers. + // Extra bits must be removed and rounding hints computed. + extra := uint(-e2) + extraMask := uint64(1<>extra, dl&extraMask + dc, fracc := dc>>extra, dc&extraMask + du, fracu := du>>extra, du&extraMask + // Is it allowed to use 'du' as a result? + // It is always allowed when it is truncated, but also + // if it is exact and the original binary mantissa is even + // When disallowed, we can subtract 1. + uok := !du0 || fracu > 0 + if du0 && fracu == 0 { + uok = mant&1 == 0 + } + if !uok { + du-- + } + // Is 'dc' the correctly rounded base 10 mantissa? + // The correct rounding might be dc+1 + cup := false // don't round up. + if dc0 { + // If we computed an exact product, the half integer + // should round to next (even) integer if 'dc' is odd. + cup = fracc > 1<<(extra-1) || + (fracc == 1<<(extra-1) && dc&1 == 1) + } else { + // otherwise, the result is a lower truncation of the ideal + // result. + cup = fracc>>(extra-1) == 1 + } + // Is 'dl' an allowed representation? + // Only if it is an exact value, and if the original binary mantissa + // was even. + lok := dl0 && fracl == 0 && (mant&1 == 0) + if !lok { + dl++ + } + // We need to remember whether the trimmed digits of 'dc' are zero. + c0 := dc0 && fracc == 0 + // render digits + ryuDigits(d, dl, dc, du, c0, cup) + d.dp -= q +} + +// mulByLog2Log10 returns math.Floor(x * log(2)/log(10)) for an integer x in +// the range -1600 <= x && x <= +1600. +// +// The range restriction lets us work in faster integer arithmetic instead of +// slower floating point arithmetic. Correctness is verified by unit tests. +func mulByLog2Log10(x int) int { + // log(2)/log(10) ≈ 0.30102999566 ≈ 78913 / 2^18 + return (x * 78913) >> 18 +} + +// mulByLog10Log2 returns math.Floor(x * log(10)/log(2)) for an integer x in +// the range -500 <= x && x <= +500. +// +// The range restriction lets us work in faster integer arithmetic instead of +// slower floating point arithmetic. Correctness is verified by unit tests. +func mulByLog10Log2(x int) int { + // log(10)/log(2) ≈ 3.32192809489 ≈ 108853 / 2^15 + return (x * 108853) >> 15 +} + +// computeBounds returns a floating-point vector (l, c, u)×2^e2 +// where the mantissas are 55-bit (or 26-bit) integers, describing the interval +// represented by the input float64 or float32. +func computeBounds(mant uint64, exp int, flt *floatInfo) (lower, central, upper uint64, e2 int) { + if mant != 1< 5e8) || (clo == 5e8 && cup) + ryuDigits32(d, lhi, chi, uhi, c0, cup, 8) + d.dp += 9 + } else { + d.nd = 0 + // emit high part + n := uint(9) + for v := chi; v > 0; { + v1, v2 := v/10, v%10 + v = v1 + n-- + d.d[n] = byte(v2 + '0') + } + d.d = d.d[n:] + d.nd = int(9 - n) + // emit low part + ryuDigits32(d, llo, clo, ulo, + c0, cup, d.nd+8) + } + // trim trailing zeros + for d.nd > 0 && d.d[d.nd-1] == '0' { + d.nd-- + } + // trim initial zeros + for d.nd > 0 && d.d[0] == '0' { + d.nd-- + d.dp-- + d.d = d.d[1:] + } +} + +// ryuDigits32 emits decimal digits for a number less than 1e9. +func ryuDigits32(d *decimalSlice, lower, central, upper uint32, + c0, cup bool, endindex int) { + if upper == 0 { + d.dp = endindex + 1 + return + } + trimmed := 0 + // Remember last trimmed digit to check for round-up. + // c0 will be used to remember zeroness of following digits. + cNextDigit := 0 + for upper > 0 { + // Repeatedly compute: + // l = Ceil(lower / 10^k) + // c = Round(central / 10^k) + // u = Floor(upper / 10^k) + // and stop when c goes out of the (l, u) interval. + l := (lower + 9) / 10 + c, cdigit := central/10, central%10 + u := upper / 10 + if l > u { + // don't trim the last digit as it is forbidden to go below l + // other, trim and exit now. + break + } + // Check that we didn't cross the lower boundary. + // The case where l < u but c == l-1 is essentially impossible, + // but may happen if: + // lower = ..11 + // central = ..19 + // upper = ..31 + // and means that 'central' is very close but less than + // an integer ending with many zeros, and usually + // the "round-up" logic hides the problem. + if l == c+1 && c < u { + c++ + cdigit = 0 + cup = false + } + trimmed++ + // Remember trimmed digits of c + c0 = c0 && cNextDigit == 0 + cNextDigit = int(cdigit) + lower, central, upper = l, c, u + } + // should we round up? + if trimmed > 0 { + cup = cNextDigit > 5 || + (cNextDigit == 5 && !c0) || + (cNextDigit == 5 && c0 && central&1 == 1) + } + if central < upper && cup { + central++ + } + // We know where the number ends, fill directly + endindex -= trimmed + v := central + n := endindex + for n > d.nd { + v1, v2 := v/100, v%100 + d.d[n] = smallsString[2*v2+1] + d.d[n-1] = smallsString[2*v2+0] + n -= 2 + v = v1 + } + if n == d.nd { + d.d[n] = byte(v + '0') + } + d.nd = endindex + 1 + d.dp = d.nd + trimmed +} + +// mult64bitPow10 takes a floating-point input with a 25-bit +// mantissa and multiplies it with 10^q. The resulting mantissa +// is m*P >> 57 where P is a 64-bit element of the detailedPowersOfTen tables. +// It is typically 31 or 32-bit wide. +// The returned boolean is true if all trimmed bits were zero. +// +// That is: +// +// m*2^e2 * round(10^q) = resM * 2^resE + ε +// exact = ε == 0 +func mult64bitPow10(m uint32, e2, q int) (resM uint32, resE int, exact bool) { + if q == 0 { + // P == 1<<63 + return m << 6, e2 - 6, true + } + if q < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < q { + // This never happens due to the range of float32/float64 exponent + panic("mult64bitPow10: power of 10 is out of range") + } + pow := detailedPowersOfTen[q-detailedPowersOfTenMinExp10][1] + if q < 0 { + // Inverse powers of ten must be rounded up. + pow += 1 + } + hi, lo := bits.Mul64(uint64(m), pow) + e2 += mulByLog10Log2(q) - 63 + 57 + return uint32(hi<<7 | lo>>57), e2, lo<<7 == 0 +} + +// mult128bitPow10 takes a floating-point input with a 55-bit +// mantissa and multiplies it with 10^q. The resulting mantissa +// is m*P >> 119 where P is a 128-bit element of the detailedPowersOfTen tables. +// It is typically 63 or 64-bit wide. +// The returned boolean is true is all trimmed bits were zero. +// +// That is: +// +// m*2^e2 * round(10^q) = resM * 2^resE + ε +// exact = ε == 0 +func mult128bitPow10(m uint64, e2, q int) (resM uint64, resE int, exact bool) { + if q == 0 { + // P == 1<<127 + return m << 8, e2 - 8, true + } + if q < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < q { + // This never happens due to the range of float32/float64 exponent + panic("mult128bitPow10: power of 10 is out of range") + } + pow := detailedPowersOfTen[q-detailedPowersOfTenMinExp10] + if q < 0 { + // Inverse powers of ten must be rounded up. + pow[0] += 1 + } + e2 += mulByLog10Log2(q) - 127 + 119 + + // long multiplication + l1, l0 := bits.Mul64(m, pow[0]) + h1, h0 := bits.Mul64(m, pow[1]) + mid, carry := bits.Add64(l1, h0, 0) + h1 += carry + return h1<<9 | mid>>55, e2, mid<<9 == 0 && l0 == 0 +} + +func divisibleByPower5(m uint64, k int) bool { + if m == 0 { + return true + } + for i := 0; i < k; i++ { + if m%5 != 0 { + return false + } + m /= 5 + } + return true +} + +// divmod1e9 computes quotient and remainder of division by 1e9, +// avoiding runtime uint64 division on 32-bit platforms. +func divmod1e9(x uint64) (uint32, uint32) { + if !host32bit { + return uint32(x / 1e9), uint32(x % 1e9) + } + // Use the same sequence of operations as the amd64 compiler. + hi, _ := bits.Mul64(x>>1, 0x89705f4136b4a598) // binary digits of 1e-9 + q := hi >> 28 + return uint32(q), uint32(x - q*1e9) +} diff --git a/gnovm/stdlibs/strconv/ftoaryu_test.gno b/gnovm/stdlibs/strconv/ftoaryu_test.gno new file mode 100644 index 00000000000..bd969e8e997 --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoaryu_test.gno @@ -0,0 +1,30 @@ +// Copyright 2021 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 strconv + +import ( + "math" + "testing" +) + +func TestMulByLog2Log10(t *testing.T) { + for x := -1600; x <= +1600; x++ { + iMath := MulByLog2Log10(x) + fMath := int(math.Floor(float64(x) * math.Ln2 / math.Ln10)) + if iMath != fMath { + t.Errorf("mulByLog2Log10(%d) failed: %d vs %d\n", x, iMath, fMath) + } + } +} + +func TestMulByLog10Log2(t *testing.T) { + for x := -500; x <= +500; x++ { + iMath := MulByLog10Log2(x) + fMath := int(math.Floor(float64(x) * math.Ln10 / math.Ln2)) + if iMath != fMath { + t.Errorf("mulByLog10Log2(%d) failed: %d vs %d\n", x, iMath, fMath) + } + } +} diff --git a/gnovm/stdlibs/strconv/internal_test.gno b/gnovm/stdlibs/strconv/internal_test.gno new file mode 100644 index 00000000000..f2cceff20eb --- /dev/null +++ b/gnovm/stdlibs/strconv/internal_test.gno @@ -0,0 +1,31 @@ +// 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. + +// export access to strconv internals for tests + +package strconv + +func NewDecimal(i uint64) *decimal { + d := new(decimal) + d.Assign(i) + return d +} + +func SetOptimize(b bool) bool { + old := optimize + optimize = b + return old +} + +func ParseFloatPrefix(s string, bitSize int) (float64, int, error) { + return parseFloatPrefix(s, bitSize) +} + +func MulByLog2Log10(x int) int { + return mulByLog2Log10(x) +} + +func MulByLog10Log2(x int) int { + return mulByLog10Log2(x) +} diff --git a/gnovm/stdlibs/strconv/isprint.gno b/gnovm/stdlibs/strconv/isprint.gno new file mode 100644 index 00000000000..baa14a65bd6 --- /dev/null +++ b/gnovm/stdlibs/strconv/isprint.gno @@ -0,0 +1,752 @@ +// Copyright 2013 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. + +// Code generated by go run makeisprint.go -output isprint.go; DO NOT EDIT. + +package strconv + +// (424+133+112)*2 + (508)*4 = 3370 bytes + +var isPrint16 = []uint16{ + 0x0020, 0x007e, + 0x00a1, 0x0377, + 0x037a, 0x037f, + 0x0384, 0x0556, + 0x0559, 0x058a, + 0x058d, 0x05c7, + 0x05d0, 0x05ea, + 0x05ef, 0x05f4, + 0x0606, 0x070d, + 0x0710, 0x074a, + 0x074d, 0x07b1, + 0x07c0, 0x07fa, + 0x07fd, 0x082d, + 0x0830, 0x085b, + 0x085e, 0x086a, + 0x0870, 0x088e, + 0x0898, 0x098c, + 0x098f, 0x0990, + 0x0993, 0x09b2, + 0x09b6, 0x09b9, + 0x09bc, 0x09c4, + 0x09c7, 0x09c8, + 0x09cb, 0x09ce, + 0x09d7, 0x09d7, + 0x09dc, 0x09e3, + 0x09e6, 0x09fe, + 0x0a01, 0x0a0a, + 0x0a0f, 0x0a10, + 0x0a13, 0x0a39, + 0x0a3c, 0x0a42, + 0x0a47, 0x0a48, + 0x0a4b, 0x0a4d, + 0x0a51, 0x0a51, + 0x0a59, 0x0a5e, + 0x0a66, 0x0a76, + 0x0a81, 0x0ab9, + 0x0abc, 0x0acd, + 0x0ad0, 0x0ad0, + 0x0ae0, 0x0ae3, + 0x0ae6, 0x0af1, + 0x0af9, 0x0b0c, + 0x0b0f, 0x0b10, + 0x0b13, 0x0b39, + 0x0b3c, 0x0b44, + 0x0b47, 0x0b48, + 0x0b4b, 0x0b4d, + 0x0b55, 0x0b57, + 0x0b5c, 0x0b63, + 0x0b66, 0x0b77, + 0x0b82, 0x0b8a, + 0x0b8e, 0x0b95, + 0x0b99, 0x0b9f, + 0x0ba3, 0x0ba4, + 0x0ba8, 0x0baa, + 0x0bae, 0x0bb9, + 0x0bbe, 0x0bc2, + 0x0bc6, 0x0bcd, + 0x0bd0, 0x0bd0, + 0x0bd7, 0x0bd7, + 0x0be6, 0x0bfa, + 0x0c00, 0x0c39, + 0x0c3c, 0x0c4d, + 0x0c55, 0x0c5a, + 0x0c5d, 0x0c5d, + 0x0c60, 0x0c63, + 0x0c66, 0x0c6f, + 0x0c77, 0x0cb9, + 0x0cbc, 0x0ccd, + 0x0cd5, 0x0cd6, + 0x0cdd, 0x0ce3, + 0x0ce6, 0x0cf3, + 0x0d00, 0x0d4f, + 0x0d54, 0x0d63, + 0x0d66, 0x0d96, + 0x0d9a, 0x0dbd, + 0x0dc0, 0x0dc6, + 0x0dca, 0x0dca, + 0x0dcf, 0x0ddf, + 0x0de6, 0x0def, + 0x0df2, 0x0df4, + 0x0e01, 0x0e3a, + 0x0e3f, 0x0e5b, + 0x0e81, 0x0ebd, + 0x0ec0, 0x0ed9, + 0x0edc, 0x0edf, + 0x0f00, 0x0f6c, + 0x0f71, 0x0fda, + 0x1000, 0x10c7, + 0x10cd, 0x10cd, + 0x10d0, 0x124d, + 0x1250, 0x125d, + 0x1260, 0x128d, + 0x1290, 0x12b5, + 0x12b8, 0x12c5, + 0x12c8, 0x1315, + 0x1318, 0x135a, + 0x135d, 0x137c, + 0x1380, 0x1399, + 0x13a0, 0x13f5, + 0x13f8, 0x13fd, + 0x1400, 0x169c, + 0x16a0, 0x16f8, + 0x1700, 0x1715, + 0x171f, 0x1736, + 0x1740, 0x1753, + 0x1760, 0x1773, + 0x1780, 0x17dd, + 0x17e0, 0x17e9, + 0x17f0, 0x17f9, + 0x1800, 0x1819, + 0x1820, 0x1878, + 0x1880, 0x18aa, + 0x18b0, 0x18f5, + 0x1900, 0x192b, + 0x1930, 0x193b, + 0x1940, 0x1940, + 0x1944, 0x196d, + 0x1970, 0x1974, + 0x1980, 0x19ab, + 0x19b0, 0x19c9, + 0x19d0, 0x19da, + 0x19de, 0x1a1b, + 0x1a1e, 0x1a7c, + 0x1a7f, 0x1a89, + 0x1a90, 0x1a99, + 0x1aa0, 0x1aad, + 0x1ab0, 0x1ace, + 0x1b00, 0x1b4c, + 0x1b50, 0x1bf3, + 0x1bfc, 0x1c37, + 0x1c3b, 0x1c49, + 0x1c4d, 0x1c88, + 0x1c90, 0x1cba, + 0x1cbd, 0x1cc7, + 0x1cd0, 0x1cfa, + 0x1d00, 0x1f15, + 0x1f18, 0x1f1d, + 0x1f20, 0x1f45, + 0x1f48, 0x1f4d, + 0x1f50, 0x1f7d, + 0x1f80, 0x1fd3, + 0x1fd6, 0x1fef, + 0x1ff2, 0x1ffe, + 0x2010, 0x2027, + 0x2030, 0x205e, + 0x2070, 0x2071, + 0x2074, 0x209c, + 0x20a0, 0x20c0, + 0x20d0, 0x20f0, + 0x2100, 0x218b, + 0x2190, 0x2426, + 0x2440, 0x244a, + 0x2460, 0x2b73, + 0x2b76, 0x2cf3, + 0x2cf9, 0x2d27, + 0x2d2d, 0x2d2d, + 0x2d30, 0x2d67, + 0x2d6f, 0x2d70, + 0x2d7f, 0x2d96, + 0x2da0, 0x2e5d, + 0x2e80, 0x2ef3, + 0x2f00, 0x2fd5, + 0x2ff0, 0x2ffb, + 0x3001, 0x3096, + 0x3099, 0x30ff, + 0x3105, 0x31e3, + 0x31f0, 0xa48c, + 0xa490, 0xa4c6, + 0xa4d0, 0xa62b, + 0xa640, 0xa6f7, + 0xa700, 0xa7ca, + 0xa7d0, 0xa7d9, + 0xa7f2, 0xa82c, + 0xa830, 0xa839, + 0xa840, 0xa877, + 0xa880, 0xa8c5, + 0xa8ce, 0xa8d9, + 0xa8e0, 0xa953, + 0xa95f, 0xa97c, + 0xa980, 0xa9d9, + 0xa9de, 0xaa36, + 0xaa40, 0xaa4d, + 0xaa50, 0xaa59, + 0xaa5c, 0xaac2, + 0xaadb, 0xaaf6, + 0xab01, 0xab06, + 0xab09, 0xab0e, + 0xab11, 0xab16, + 0xab20, 0xab6b, + 0xab70, 0xabed, + 0xabf0, 0xabf9, + 0xac00, 0xd7a3, + 0xd7b0, 0xd7c6, + 0xd7cb, 0xd7fb, + 0xf900, 0xfa6d, + 0xfa70, 0xfad9, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xfb1d, 0xfbc2, + 0xfbd3, 0xfd8f, + 0xfd92, 0xfdc7, + 0xfdcf, 0xfdcf, + 0xfdf0, 0xfe19, + 0xfe20, 0xfe6b, + 0xfe70, 0xfefc, + 0xff01, 0xffbe, + 0xffc2, 0xffc7, + 0xffca, 0xffcf, + 0xffd2, 0xffd7, + 0xffda, 0xffdc, + 0xffe0, 0xffee, + 0xfffc, 0xfffd, +} + +var isNotPrint16 = []uint16{ + 0x00ad, + 0x038b, + 0x038d, + 0x03a2, + 0x0530, + 0x0590, + 0x061c, + 0x06dd, + 0x083f, + 0x085f, + 0x08e2, + 0x0984, + 0x09a9, + 0x09b1, + 0x09de, + 0x0a04, + 0x0a29, + 0x0a31, + 0x0a34, + 0x0a37, + 0x0a3d, + 0x0a5d, + 0x0a84, + 0x0a8e, + 0x0a92, + 0x0aa9, + 0x0ab1, + 0x0ab4, + 0x0ac6, + 0x0aca, + 0x0b00, + 0x0b04, + 0x0b29, + 0x0b31, + 0x0b34, + 0x0b5e, + 0x0b84, + 0x0b91, + 0x0b9b, + 0x0b9d, + 0x0bc9, + 0x0c0d, + 0x0c11, + 0x0c29, + 0x0c45, + 0x0c49, + 0x0c57, + 0x0c8d, + 0x0c91, + 0x0ca9, + 0x0cb4, + 0x0cc5, + 0x0cc9, + 0x0cdf, + 0x0cf0, + 0x0d0d, + 0x0d11, + 0x0d45, + 0x0d49, + 0x0d80, + 0x0d84, + 0x0db2, + 0x0dbc, + 0x0dd5, + 0x0dd7, + 0x0e83, + 0x0e85, + 0x0e8b, + 0x0ea4, + 0x0ea6, + 0x0ec5, + 0x0ec7, + 0x0ecf, + 0x0f48, + 0x0f98, + 0x0fbd, + 0x0fcd, + 0x10c6, + 0x1249, + 0x1257, + 0x1259, + 0x1289, + 0x12b1, + 0x12bf, + 0x12c1, + 0x12d7, + 0x1311, + 0x1680, + 0x176d, + 0x1771, + 0x180e, + 0x191f, + 0x1a5f, + 0x1b7f, + 0x1f58, + 0x1f5a, + 0x1f5c, + 0x1f5e, + 0x1fb5, + 0x1fc5, + 0x1fdc, + 0x1ff5, + 0x208f, + 0x2b96, + 0x2d26, + 0x2da7, + 0x2daf, + 0x2db7, + 0x2dbf, + 0x2dc7, + 0x2dcf, + 0x2dd7, + 0x2ddf, + 0x2e9a, + 0x3040, + 0x3130, + 0x318f, + 0x321f, + 0xa7d2, + 0xa7d4, + 0xa9ce, + 0xa9ff, + 0xab27, + 0xab2f, + 0xfb37, + 0xfb3d, + 0xfb3f, + 0xfb42, + 0xfb45, + 0xfe53, + 0xfe67, + 0xfe75, + 0xffe7, +} + +var isPrint32 = []uint32{ + 0x010000, 0x01004d, + 0x010050, 0x01005d, + 0x010080, 0x0100fa, + 0x010100, 0x010102, + 0x010107, 0x010133, + 0x010137, 0x01019c, + 0x0101a0, 0x0101a0, + 0x0101d0, 0x0101fd, + 0x010280, 0x01029c, + 0x0102a0, 0x0102d0, + 0x0102e0, 0x0102fb, + 0x010300, 0x010323, + 0x01032d, 0x01034a, + 0x010350, 0x01037a, + 0x010380, 0x0103c3, + 0x0103c8, 0x0103d5, + 0x010400, 0x01049d, + 0x0104a0, 0x0104a9, + 0x0104b0, 0x0104d3, + 0x0104d8, 0x0104fb, + 0x010500, 0x010527, + 0x010530, 0x010563, + 0x01056f, 0x0105bc, + 0x010600, 0x010736, + 0x010740, 0x010755, + 0x010760, 0x010767, + 0x010780, 0x0107ba, + 0x010800, 0x010805, + 0x010808, 0x010838, + 0x01083c, 0x01083c, + 0x01083f, 0x01089e, + 0x0108a7, 0x0108af, + 0x0108e0, 0x0108f5, + 0x0108fb, 0x01091b, + 0x01091f, 0x010939, + 0x01093f, 0x01093f, + 0x010980, 0x0109b7, + 0x0109bc, 0x0109cf, + 0x0109d2, 0x010a06, + 0x010a0c, 0x010a35, + 0x010a38, 0x010a3a, + 0x010a3f, 0x010a48, + 0x010a50, 0x010a58, + 0x010a60, 0x010a9f, + 0x010ac0, 0x010ae6, + 0x010aeb, 0x010af6, + 0x010b00, 0x010b35, + 0x010b39, 0x010b55, + 0x010b58, 0x010b72, + 0x010b78, 0x010b91, + 0x010b99, 0x010b9c, + 0x010ba9, 0x010baf, + 0x010c00, 0x010c48, + 0x010c80, 0x010cb2, + 0x010cc0, 0x010cf2, + 0x010cfa, 0x010d27, + 0x010d30, 0x010d39, + 0x010e60, 0x010ead, + 0x010eb0, 0x010eb1, + 0x010efd, 0x010f27, + 0x010f30, 0x010f59, + 0x010f70, 0x010f89, + 0x010fb0, 0x010fcb, + 0x010fe0, 0x010ff6, + 0x011000, 0x01104d, + 0x011052, 0x011075, + 0x01107f, 0x0110c2, + 0x0110d0, 0x0110e8, + 0x0110f0, 0x0110f9, + 0x011100, 0x011147, + 0x011150, 0x011176, + 0x011180, 0x0111f4, + 0x011200, 0x011241, + 0x011280, 0x0112a9, + 0x0112b0, 0x0112ea, + 0x0112f0, 0x0112f9, + 0x011300, 0x01130c, + 0x01130f, 0x011310, + 0x011313, 0x011344, + 0x011347, 0x011348, + 0x01134b, 0x01134d, + 0x011350, 0x011350, + 0x011357, 0x011357, + 0x01135d, 0x011363, + 0x011366, 0x01136c, + 0x011370, 0x011374, + 0x011400, 0x011461, + 0x011480, 0x0114c7, + 0x0114d0, 0x0114d9, + 0x011580, 0x0115b5, + 0x0115b8, 0x0115dd, + 0x011600, 0x011644, + 0x011650, 0x011659, + 0x011660, 0x01166c, + 0x011680, 0x0116b9, + 0x0116c0, 0x0116c9, + 0x011700, 0x01171a, + 0x01171d, 0x01172b, + 0x011730, 0x011746, + 0x011800, 0x01183b, + 0x0118a0, 0x0118f2, + 0x0118ff, 0x011906, + 0x011909, 0x011909, + 0x01190c, 0x011938, + 0x01193b, 0x011946, + 0x011950, 0x011959, + 0x0119a0, 0x0119a7, + 0x0119aa, 0x0119d7, + 0x0119da, 0x0119e4, + 0x011a00, 0x011a47, + 0x011a50, 0x011aa2, + 0x011ab0, 0x011af8, + 0x011b00, 0x011b09, + 0x011c00, 0x011c45, + 0x011c50, 0x011c6c, + 0x011c70, 0x011c8f, + 0x011c92, 0x011cb6, + 0x011d00, 0x011d36, + 0x011d3a, 0x011d47, + 0x011d50, 0x011d59, + 0x011d60, 0x011d98, + 0x011da0, 0x011da9, + 0x011ee0, 0x011ef8, + 0x011f00, 0x011f3a, + 0x011f3e, 0x011f59, + 0x011fb0, 0x011fb0, + 0x011fc0, 0x011ff1, + 0x011fff, 0x012399, + 0x012400, 0x012474, + 0x012480, 0x012543, + 0x012f90, 0x012ff2, + 0x013000, 0x01342f, + 0x013440, 0x013455, + 0x014400, 0x014646, + 0x016800, 0x016a38, + 0x016a40, 0x016a69, + 0x016a6e, 0x016ac9, + 0x016ad0, 0x016aed, + 0x016af0, 0x016af5, + 0x016b00, 0x016b45, + 0x016b50, 0x016b77, + 0x016b7d, 0x016b8f, + 0x016e40, 0x016e9a, + 0x016f00, 0x016f4a, + 0x016f4f, 0x016f87, + 0x016f8f, 0x016f9f, + 0x016fe0, 0x016fe4, + 0x016ff0, 0x016ff1, + 0x017000, 0x0187f7, + 0x018800, 0x018cd5, + 0x018d00, 0x018d08, + 0x01aff0, 0x01b122, + 0x01b132, 0x01b132, + 0x01b150, 0x01b152, + 0x01b155, 0x01b155, + 0x01b164, 0x01b167, + 0x01b170, 0x01b2fb, + 0x01bc00, 0x01bc6a, + 0x01bc70, 0x01bc7c, + 0x01bc80, 0x01bc88, + 0x01bc90, 0x01bc99, + 0x01bc9c, 0x01bc9f, + 0x01cf00, 0x01cf2d, + 0x01cf30, 0x01cf46, + 0x01cf50, 0x01cfc3, + 0x01d000, 0x01d0f5, + 0x01d100, 0x01d126, + 0x01d129, 0x01d172, + 0x01d17b, 0x01d1ea, + 0x01d200, 0x01d245, + 0x01d2c0, 0x01d2d3, + 0x01d2e0, 0x01d2f3, + 0x01d300, 0x01d356, + 0x01d360, 0x01d378, + 0x01d400, 0x01d49f, + 0x01d4a2, 0x01d4a2, + 0x01d4a5, 0x01d4a6, + 0x01d4a9, 0x01d50a, + 0x01d50d, 0x01d546, + 0x01d54a, 0x01d6a5, + 0x01d6a8, 0x01d7cb, + 0x01d7ce, 0x01da8b, + 0x01da9b, 0x01daaf, + 0x01df00, 0x01df1e, + 0x01df25, 0x01df2a, + 0x01e000, 0x01e018, + 0x01e01b, 0x01e02a, + 0x01e030, 0x01e06d, + 0x01e08f, 0x01e08f, + 0x01e100, 0x01e12c, + 0x01e130, 0x01e13d, + 0x01e140, 0x01e149, + 0x01e14e, 0x01e14f, + 0x01e290, 0x01e2ae, + 0x01e2c0, 0x01e2f9, + 0x01e2ff, 0x01e2ff, + 0x01e4d0, 0x01e4f9, + 0x01e7e0, 0x01e8c4, + 0x01e8c7, 0x01e8d6, + 0x01e900, 0x01e94b, + 0x01e950, 0x01e959, + 0x01e95e, 0x01e95f, + 0x01ec71, 0x01ecb4, + 0x01ed01, 0x01ed3d, + 0x01ee00, 0x01ee24, + 0x01ee27, 0x01ee3b, + 0x01ee42, 0x01ee42, + 0x01ee47, 0x01ee54, + 0x01ee57, 0x01ee64, + 0x01ee67, 0x01ee9b, + 0x01eea1, 0x01eebb, + 0x01eef0, 0x01eef1, + 0x01f000, 0x01f02b, + 0x01f030, 0x01f093, + 0x01f0a0, 0x01f0ae, + 0x01f0b1, 0x01f0f5, + 0x01f100, 0x01f1ad, + 0x01f1e6, 0x01f202, + 0x01f210, 0x01f23b, + 0x01f240, 0x01f248, + 0x01f250, 0x01f251, + 0x01f260, 0x01f265, + 0x01f300, 0x01f6d7, + 0x01f6dc, 0x01f6ec, + 0x01f6f0, 0x01f6fc, + 0x01f700, 0x01f776, + 0x01f77b, 0x01f7d9, + 0x01f7e0, 0x01f7eb, + 0x01f7f0, 0x01f7f0, + 0x01f800, 0x01f80b, + 0x01f810, 0x01f847, + 0x01f850, 0x01f859, + 0x01f860, 0x01f887, + 0x01f890, 0x01f8ad, + 0x01f8b0, 0x01f8b1, + 0x01f900, 0x01fa53, + 0x01fa60, 0x01fa6d, + 0x01fa70, 0x01fa7c, + 0x01fa80, 0x01fa88, + 0x01fa90, 0x01fac5, + 0x01face, 0x01fadb, + 0x01fae0, 0x01fae8, + 0x01faf0, 0x01faf8, + 0x01fb00, 0x01fbca, + 0x01fbf0, 0x01fbf9, + 0x020000, 0x02a6df, + 0x02a700, 0x02b739, + 0x02b740, 0x02b81d, + 0x02b820, 0x02cea1, + 0x02ceb0, 0x02ebe0, + 0x02f800, 0x02fa1d, + 0x030000, 0x03134a, + 0x031350, 0x0323af, + 0x0e0100, 0x0e01ef, +} + +var isNotPrint32 = []uint16{ // add 0x10000 to each entry + 0x000c, + 0x0027, + 0x003b, + 0x003e, + 0x018f, + 0x039e, + 0x057b, + 0x058b, + 0x0593, + 0x0596, + 0x05a2, + 0x05b2, + 0x05ba, + 0x0786, + 0x07b1, + 0x0809, + 0x0836, + 0x0856, + 0x08f3, + 0x0a04, + 0x0a14, + 0x0a18, + 0x0e7f, + 0x0eaa, + 0x10bd, + 0x1135, + 0x11e0, + 0x1212, + 0x1287, + 0x1289, + 0x128e, + 0x129e, + 0x1304, + 0x1329, + 0x1331, + 0x1334, + 0x133a, + 0x145c, + 0x1914, + 0x1917, + 0x1936, + 0x1c09, + 0x1c37, + 0x1ca8, + 0x1d07, + 0x1d0a, + 0x1d3b, + 0x1d3e, + 0x1d66, + 0x1d69, + 0x1d8f, + 0x1d92, + 0x1f11, + 0x246f, + 0x6a5f, + 0x6abf, + 0x6b5a, + 0x6b62, + 0xaff4, + 0xaffc, + 0xafff, + 0xd455, + 0xd49d, + 0xd4ad, + 0xd4ba, + 0xd4bc, + 0xd4c4, + 0xd506, + 0xd515, + 0xd51d, + 0xd53a, + 0xd53f, + 0xd545, + 0xd551, + 0xdaa0, + 0xe007, + 0xe022, + 0xe025, + 0xe7e7, + 0xe7ec, + 0xe7ef, + 0xe7ff, + 0xee04, + 0xee20, + 0xee23, + 0xee28, + 0xee33, + 0xee38, + 0xee3a, + 0xee48, + 0xee4a, + 0xee4c, + 0xee50, + 0xee53, + 0xee58, + 0xee5a, + 0xee5c, + 0xee5e, + 0xee60, + 0xee63, + 0xee6b, + 0xee73, + 0xee78, + 0xee7d, + 0xee7f, + 0xee8a, + 0xeea4, + 0xeeaa, + 0xf0c0, + 0xf0d0, + 0xfabe, + 0xfb93, +} + +// isGraphic lists the graphic runes not matched by IsPrint. +var isGraphic = []uint16{ + 0x00a0, + 0x1680, + 0x2000, + 0x2001, + 0x2002, + 0x2003, + 0x2004, + 0x2005, + 0x2006, + 0x2007, + 0x2008, + 0x2009, + 0x200a, + 0x202f, + 0x205f, + 0x3000, +} diff --git a/gnovm/stdlibs/strconv/itoa.gno b/gnovm/stdlibs/strconv/itoa.gno new file mode 100644 index 00000000000..b0c2666e7cb --- /dev/null +++ b/gnovm/stdlibs/strconv/itoa.gno @@ -0,0 +1,205 @@ +// 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 strconv + +import "math/bits" + +const fastSmalls = true // enable fast path for small integers + +// FormatUint returns the string representation of i in the given base, +// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' +// for digit values >= 10. +func FormatUint(i uint64, base int) string { + if fastSmalls && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, i, base, false, false) + return s +} + +// FormatInt returns the string representation of i in the given base, +// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' +// for digit values >= 10. +func FormatInt(i int64, base int) string { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, uint64(i), base, i < 0, false) + return s +} + +// Itoa is equivalent to FormatInt(int64(i), 10). +func Itoa(i int) string { + return FormatInt(int64(i), 10) +} + +// AppendInt appends the string form of the integer i, +// as generated by FormatInt, to dst and returns the extended buffer. +func AppendInt(dst []byte, i int64, base int) []byte { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, uint64(i), base, i < 0, true) + return dst +} + +// AppendUint appends the string form of the unsigned integer i, +// as generated by FormatUint, to dst and returns the extended buffer. +func AppendUint(dst []byte, i uint64, base int) []byte { + if fastSmalls && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, i, base, false, true) + return dst +} + +// small returns the string for an i with 0 <= i < nSmalls. +func small(i int) string { + if i < 10 { + return digits[i : i+1] + } + return smallsString[i*2 : i*2+2] +} + +const nSmalls = 100 + +const smallsString = "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" + +const host32bit = ^uint(0)>>32 == 0 + +const digits = "0123456789abcdefghijklmnopqrstuvwxyz" + +// formatBits computes the string representation of u in the given base. +// If neg is set, u is treated as negative int64 value. If append_ is +// set, the string is appended to dst and the resulting byte slice is +// returned as the first result value; otherwise the string is returned +// as the second result value. +func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) { + if base < 2 || base > len(digits) { + panic("strconv: illegal AppendInt/FormatInt base") + } + // 2 <= base && base <= len(digits) + + var a [64 + 1]byte // +1 for sign of 64bit value in base 2 + i := len(a) + + if neg { + u = -u + } + + // convert bits + // We use uint values where we can because those will + // fit into a single register even on a 32bit machine. + if base == 10 { + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if host32bit { + // convert the lower digits using 32bit operations + for u >= 1e9 { + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / 1e9 + us := uint(u - q*1e9) // u % 1e9 fits into a uint + for j := 4; j > 0; j-- { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 10, since it contains the last digit + // from the initial 9-digit us. + i-- + a[i] = smallsString[us*2+1] + + u = q + } + // u < 1e9 + } + + // u guaranteed to fit into a uint + us := uint(u) + for us >= 100 { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 100 + is := us * 2 + i-- + a[i] = smallsString[is+1] + if us >= 10 { + i-- + a[i] = smallsString[is] + } + + } else if isPowerOfTwo(base) { + // Use shifts and masks instead of / and %. + // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36. + // The largest power of 2 below or equal to 36 is 32, which is 1 << 5; + // i.e., the largest possible shift count is 5. By &-ind that value with + // the constant 7 we tell the compiler that the shift count is always + // less than 8 which is smaller than any register width. This allows + // the compiler to generate better code for the shift operation. + shift := uint(bits.TrailingZeros(uint(base))) & 7 + b := uint64(base) + m := uint(base) - 1 // == 1<= b { + i-- + a[i] = digits[uint(u)&m] + u >>= shift + } + // u < base + i-- + a[i] = digits[uint(u)] + } else { + // general case + b := uint64(base) + for u >= b { + i-- + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q + } + // u < base + i-- + a[i] = digits[uint(u)] + } + + // add sign, if any + if neg { + i-- + a[i] = '-' + } + + if append_ { + d = append(dst, a[i:]...) + return + } + s = string(a[i:]) + return +} + +func isPowerOfTwo(x int) bool { + return x&(x-1) == 0 +} diff --git a/gnovm/stdlibs/strconv/itoa_test.gno b/gnovm/stdlibs/strconv/itoa_test.gno new file mode 100644 index 00000000000..b76acc78183 --- /dev/null +++ b/gnovm/stdlibs/strconv/itoa_test.gno @@ -0,0 +1,242 @@ +// 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 strconv + +import ( + "testing" +) + +type itob64Test struct { + in int64 + base int + out string +} + +var itob64tests = []itob64Test{ + {0, 10, "0"}, + {1, 10, "1"}, + {-1, 10, "-1"}, + {12345678, 10, "12345678"}, + {-987654321, 10, "-987654321"}, + {1<<31 - 1, 10, "2147483647"}, + {-1<<31 + 1, 10, "-2147483647"}, + {1 << 31, 10, "2147483648"}, + {-1 << 31, 10, "-2147483648"}, + {1<<31 + 1, 10, "2147483649"}, + {-1<<31 - 1, 10, "-2147483649"}, + {1<<32 - 1, 10, "4294967295"}, + {-1<<32 + 1, 10, "-4294967295"}, + {1 << 32, 10, "4294967296"}, + {-1 << 32, 10, "-4294967296"}, + {1<<32 + 1, 10, "4294967297"}, + {-1<<32 - 1, 10, "-4294967297"}, + {1 << 50, 10, "1125899906842624"}, + {1<<63 - 1, 10, "9223372036854775807"}, + {-1<<63 + 1, 10, "-9223372036854775807"}, + {-1 << 63, 10, "-9223372036854775808"}, + + {0, 2, "0"}, + {10, 2, "1010"}, + {-1, 2, "-1"}, + {1 << 15, 2, "1000000000000000"}, + + {-8, 8, "-10"}, + {057635436545, 8, "57635436545"}, + {1 << 24, 8, "100000000"}, + + {16, 16, "10"}, + {-0x123456789abcdef, 16, "-123456789abcdef"}, + {1<<63 - 1, 16, "7fffffffffffffff"}, + {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"}, + {-1 << 63, 2, "-1000000000000000000000000000000000000000000000000000000000000000"}, + + {16, 17, "g"}, + {25, 25, "10"}, + {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"}, + {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"}, +} + +func TestItoa(t *testing.T) { + for _, test := range itob64tests { + s := FormatInt(test.in, test.base) + if s != test.out { + t.Errorf("FormatInt(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + x := AppendInt([]byte("abc"), test.in, test.base) + if string(x) != "abc"+test.out { + t.Errorf("AppendInt(%q, %v, %v) = %q want %v", + "abc", test.in, test.base, x, test.out) + } + + if test.in >= 0 { + s := FormatUint(uint64(test.in), test.base) + if s != test.out { + t.Errorf("FormatUint(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + x := AppendUint(nil, uint64(test.in), test.base) + if string(x) != test.out { + t.Errorf("AppendUint(%q, %v, %v) = %q want %v", + "abc", uint64(test.in), test.base, x, test.out) + } + } + + if test.base == 10 && int64(int(test.in)) == test.in { + s := Itoa(int(test.in)) + if s != test.out { + t.Errorf("Itoa(%v) = %v want %v", + test.in, s, test.out) + } + } + } + + // Override when base is illegal + defer func() { + if r := recover(); r == nil { + t.Fatalf("expected panic due to illegal base") + } + }() + FormatUint(12345678, 1) +} + +type uitob64Test struct { + in uint64 + base int + out string +} + +var uitob64tests = []uitob64Test{ + {1<<63 - 1, 10, "9223372036854775807"}, + {1 << 63, 10, "9223372036854775808"}, + {1<<63 + 1, 10, "9223372036854775809"}, + {1<<64 - 2, 10, "18446744073709551614"}, + {1<<64 - 1, 10, "18446744073709551615"}, + {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"}, +} + +func TestUitoa(t *testing.T) { + for _, test := range uitob64tests { + s := FormatUint(test.in, test.base) + if s != test.out { + t.Errorf("FormatUint(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + x := AppendUint([]byte("abc"), test.in, test.base) + if string(x) != "abc"+test.out { + t.Errorf("AppendUint(%q, %v, %v) = %q want %v", + "abc", test.in, test.base, x, test.out) + } + + } +} + +var varlenUints = []struct { + in uint64 + out string +}{ + {1, "1"}, + {12, "12"}, + {123, "123"}, + {1234, "1234"}, + {12345, "12345"}, + {123456, "123456"}, + {1234567, "1234567"}, + {12345678, "12345678"}, + {123456789, "123456789"}, + {1234567890, "1234567890"}, + {12345678901, "12345678901"}, + {123456789012, "123456789012"}, + {1234567890123, "1234567890123"}, + {12345678901234, "12345678901234"}, + {123456789012345, "123456789012345"}, + {1234567890123456, "1234567890123456"}, + {12345678901234567, "12345678901234567"}, + {123456789012345678, "123456789012345678"}, + {1234567890123456789, "1234567890123456789"}, + {12345678901234567890, "12345678901234567890"}, +} + +func TestFormatUintVarlen(t *testing.T) { + for _, test := range varlenUints { + s := FormatUint(test.in, 10) + if s != test.out { + t.Errorf("FormatUint(%v, 10) = %v want %v", test.in, s, test.out) + } + } +} + +func BenchmarkFormatInt(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range itob64tests { + s := FormatInt(test.in, test.base) + BenchSink += len(s) + } + } +} + +func BenchmarkAppendInt(b *testing.B) { + dst := make([]byte, 0, 30) + for i := 0; i < b.N; i++ { + for _, test := range itob64tests { + dst = AppendInt(dst[:0], test.in, test.base) + BenchSink += len(dst) + } + } +} + +func BenchmarkFormatUint(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range uitob64tests { + s := FormatUint(test.in, test.base) + BenchSink += len(s) + } + } +} + +func BenchmarkAppendUint(b *testing.B) { + dst := make([]byte, 0, 30) + for i := 0; i < b.N; i++ { + for _, test := range uitob64tests { + dst = AppendUint(dst[:0], test.in, test.base) + BenchSink += len(dst) + } + } +} + +func BenchmarkFormatIntSmall(b *testing.B) { + smallInts := []int64{7, 42} + for _, smallInt := range smallInts { + b.Run(Itoa(int(smallInt)), func(b *testing.B) { + for i := 0; i < b.N; i++ { + s := FormatInt(smallInt, 10) + BenchSink += len(s) + } + }) + } +} + +func BenchmarkAppendIntSmall(b *testing.B) { + dst := make([]byte, 0, 30) + const smallInt = 42 + for i := 0; i < b.N; i++ { + dst = AppendInt(dst[:0], smallInt, 10) + BenchSink += len(dst) + } +} + +func BenchmarkAppendUintVarlen(b *testing.B) { + for _, test := range varlenUints { + b.Run(test.out, func(b *testing.B) { + dst := make([]byte, 0, 30) + for j := 0; j < b.N; j++ { + dst = AppendUint(dst[:0], test.in, 10) + BenchSink += len(dst) + } + }) + } +} + +var BenchSink int // make sure compiler cannot optimize away benchmarks diff --git a/gnovm/stdlibs/strconv/quote.gno b/gnovm/stdlibs/strconv/quote.gno new file mode 100644 index 00000000000..7c384336795 --- /dev/null +++ b/gnovm/stdlibs/strconv/quote.gno @@ -0,0 +1,599 @@ +// 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. + +//go:generate go run makeisprint.go -output isprint.go + +package strconv + +import ( + "unicode/utf8" +) + +const ( + lowerhex = "0123456789abcdef" + upperhex = "0123456789ABCDEF" +) + +// contains reports whether the string contains the byte c. +func contains(s string, c byte) bool { + return index(s, c) != -1 +} + +func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string { + return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly)) +} + +func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string { + return string(appendQuotedRuneWith(nil, r, quote, ASCIIonly, graphicOnly)) +} + +func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte { + // Often called with big strings, so preallocate. If there's quoting, + // this is conservative but still helps a lot. + if cap(buf)-len(buf) < len(s) { + nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1) + copy(nBuf, buf) + buf = nBuf + } + buf = append(buf, quote) + for width := 0; len(s) > 0; s = s[width:] { + r := rune(s[0]) + width = 1 + if r >= utf8.RuneSelf { + r, width = utf8.DecodeRuneInString(s) + } + if width == 1 && r == utf8.RuneError { + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[s[0]>>4]) + buf = append(buf, lowerhex[s[0]&0xF]) + continue + } + buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly) + } + buf = append(buf, quote) + return buf +} + +func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte { + buf = append(buf, quote) + if !utf8.ValidRune(r) { + r = utf8.RuneError + } + buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly) + buf = append(buf, quote) + return buf +} + +func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte { + if r == rune(quote) || r == '\\' { // always backslashed + buf = append(buf, '\\') + buf = append(buf, byte(r)) + return buf + } + if ASCIIonly { + if r < utf8.RuneSelf && IsPrint(r) { + buf = append(buf, byte(r)) + return buf + } + } else if IsPrint(r) || graphicOnly && isInGraphicList(r) { + return utf8.AppendRune(buf, r) + } + switch r { + case '\a': + buf = append(buf, `\a`...) + case '\b': + buf = append(buf, `\b`...) + case '\f': + buf = append(buf, `\f`...) + case '\n': + buf = append(buf, `\n`...) + case '\r': + buf = append(buf, `\r`...) + case '\t': + buf = append(buf, `\t`...) + case '\v': + buf = append(buf, `\v`...) + default: + switch { + case r < ' ' || r == 0x7f: + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[byte(r)>>4]) + buf = append(buf, lowerhex[byte(r)&0xF]) + case !utf8.ValidRune(r): + r = 0xFFFD + fallthrough + case r < 0x10000: + buf = append(buf, `\u`...) + for s := 12; s >= 0; s -= 4 { + buf = append(buf, lowerhex[r>>uint(s)&0xF]) + } + default: + buf = append(buf, `\U`...) + for s := 28; s >= 0; s -= 4 { + buf = append(buf, lowerhex[r>>uint(s)&0xF]) + } + } + } + return buf +} + +// Quote returns a double-quoted Go string literal representing s. The +// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for +// control characters and non-printable characters as defined by +// IsPrint. +func Quote(s string) string { + return quoteWith(s, '"', false, false) +} + +// AppendQuote appends a double-quoted Go string literal representing s, +// as generated by Quote, to dst and returns the extended buffer. +func AppendQuote(dst []byte, s string) []byte { + return appendQuotedWith(dst, s, '"', false, false) +} + +// QuoteToASCII returns a double-quoted Go string literal representing s. +// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for +// non-ASCII characters and non-printable characters as defined by IsPrint. +func QuoteToASCII(s string) string { + return quoteWith(s, '"', true, false) +} + +// AppendQuoteToASCII appends a double-quoted Go string literal representing s, +// as generated by QuoteToASCII, to dst and returns the extended buffer. +func AppendQuoteToASCII(dst []byte, s string) []byte { + return appendQuotedWith(dst, s, '"', true, false) +} + +// QuoteToGraphic returns a double-quoted Go string literal representing s. +// The returned string leaves Unicode graphic characters, as defined by +// IsGraphic, unchanged and uses Go escape sequences (\t, \n, \xFF, \u0100) +// for non-graphic characters. +func QuoteToGraphic(s string) string { + return quoteWith(s, '"', false, true) +} + +// AppendQuoteToGraphic appends a double-quoted Go string literal representing s, +// as generated by QuoteToGraphic, to dst and returns the extended buffer. +func AppendQuoteToGraphic(dst []byte, s string) []byte { + return appendQuotedWith(dst, s, '"', false, true) +} + +// QuoteRune returns a single-quoted Go character literal representing the +// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) +// for control characters and non-printable characters as defined by IsPrint. +// If r is not a valid Unicode code point, it is interpreted as the Unicode +// replacement character U+FFFD. +func QuoteRune(r rune) string { + return quoteRuneWith(r, '\'', false, false) +} + +// AppendQuoteRune appends a single-quoted Go character literal representing the rune, +// as generated by QuoteRune, to dst and returns the extended buffer. +func AppendQuoteRune(dst []byte, r rune) []byte { + return appendQuotedRuneWith(dst, r, '\'', false, false) +} + +// QuoteRuneToASCII returns a single-quoted Go character literal representing +// the rune. The returned string uses Go escape sequences (\t, \n, \xFF, +// \u0100) for non-ASCII characters and non-printable characters as defined +// by IsPrint. +// If r is not a valid Unicode code point, it is interpreted as the Unicode +// replacement character U+FFFD. +func QuoteRuneToASCII(r rune) string { + return quoteRuneWith(r, '\'', true, false) +} + +// AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune, +// as generated by QuoteRuneToASCII, to dst and returns the extended buffer. +func AppendQuoteRuneToASCII(dst []byte, r rune) []byte { + return appendQuotedRuneWith(dst, r, '\'', true, false) +} + +// QuoteRuneToGraphic returns a single-quoted Go character literal representing +// the rune. If the rune is not a Unicode graphic character, +// as defined by IsGraphic, the returned string will use a Go escape sequence +// (\t, \n, \xFF, \u0100). +// If r is not a valid Unicode code point, it is interpreted as the Unicode +// replacement character U+FFFD. +func QuoteRuneToGraphic(r rune) string { + return quoteRuneWith(r, '\'', false, true) +} + +// AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune, +// as generated by QuoteRuneToGraphic, to dst and returns the extended buffer. +func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte { + return appendQuotedRuneWith(dst, r, '\'', false, true) +} + +// CanBackquote reports whether the string s can be represented +// unchanged as a single-line backquoted string without control +// characters other than tab. +func CanBackquote(s string) bool { + for len(s) > 0 { + r, wid := utf8.DecodeRuneInString(s) + s = s[wid:] + if wid > 1 { + if r == '\ufeff' { + return false // BOMs are invisible and should not be quoted. + } + continue // All other multibyte runes are correctly encoded and assumed printable. + } + if r == utf8.RuneError { + return false + } + if (r < ' ' && r != '\t') || r == '`' || r == '\u007F' { + return false + } + } + return true +} + +func unhex(b byte) (v rune, ok bool) { + c := rune(b) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + return +} + +// UnquoteChar decodes the first character or byte in the escaped string +// or character literal represented by the string s. +// It returns four values: +// +// 1. value, the decoded Unicode code point or byte value; +// 2. multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation; +// 3. tail, the remainder of the string after the character; and +// 4. an error that will be nil if the character is syntactically valid. +// +// The second argument, quote, specifies the type of literal being parsed +// and therefore which escaped quote character is permitted. +// If set to a single quote, it permits the sequence \' and disallows unescaped '. +// If set to a double quote, it permits \" and disallows unescaped ". +// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped. +func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { + // easy cases + if len(s) == 0 { + err = ErrSyntax + return + } + switch c := s[0]; { + case c == quote && (quote == '\'' || quote == '"'): + err = ErrSyntax + return + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s) + return r, true, s[size:], nil + case c != '\\': + return rune(s[0]), false, s[1:], nil + } + + // hard case: c is backslash + if len(s) <= 1 { + err = ErrSyntax + return + } + c := s[1] + s = s[2:] + + switch c { + case 'a': + value = '\a' + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u', 'U': + n := 0 + switch c { + case 'x': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + var v rune + if len(s) < n { + err = ErrSyntax + return + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]) + if !ok { + err = ErrSyntax + return + } + v = v<<4 | x + } + s = s[n:] + if c == 'x' { + // single-byte string, possibly not UTF-8 + value = v + break + } + if !utf8.ValidRune(v) { + err = ErrSyntax + return + } + value = v + multibyte = true + case '0', '1', '2', '3', '4', '5', '6', '7': + v := rune(c) - '0' + if len(s) < 2 { + err = ErrSyntax + return + } + for j := 0; j < 2; j++ { // one digit already; two more + x := rune(s[j]) - '0' + if x < 0 || x > 7 { + err = ErrSyntax + return + } + v = (v << 3) | x + } + s = s[2:] + if v > 255 { + err = ErrSyntax + return + } + value = v + case '\\': + value = '\\' + case '\'', '"': + if c != quote { + err = ErrSyntax + return + } + value = rune(c) + default: + err = ErrSyntax + return + } + tail = s + return +} + +// QuotedPrefix returns the quoted string (as understood by Unquote) at the prefix of s. +// If s does not start with a valid quoted string, QuotedPrefix returns an error. +func QuotedPrefix(s string) (string, error) { + out, _, err := unquote(s, false) + return out, err +} + +// Unquote interprets s as a single-quoted, double-quoted, +// or backquoted Go string literal, returning the string value +// that s quotes. (If s is single-quoted, it would be a Go +// character literal; Unquote returns the corresponding +// one-character string.) +func Unquote(s string) (string, error) { + out, rem, err := unquote(s, true) + if len(rem) > 0 { + return "", ErrSyntax + } + return out, err +} + +// unquote parses a quoted string at the start of the input, +// returning the parsed prefix, the remaining suffix, and any parse errors. +// If unescape is true, the parsed prefix is unescaped, +// otherwise the input prefix is provided verbatim. +func unquote(in string, unescape bool) (out, rem string, err error) { + // Determine the quote form and optimistically find the terminating quote. + if len(in) < 2 { + return "", in, ErrSyntax + } + quote := in[0] + end := index(in[1:], quote) + if end < 0 { + return "", in, ErrSyntax + } + end += 2 // position after terminating quote; may be wrong if escape sequences are present + + switch quote { + case '`': + switch { + case !unescape: + out = in[:end] // include quotes + case !contains(in[:end], '\r'): + out = in[len("`") : end-len("`")] // exclude quotes + default: + // Carriage return characters ('\r') inside raw string literals + // are discarded from the raw string value. + buf := make([]byte, 0, end-len("`")-len("\r")-len("`")) + for i := len("`"); i < end-len("`"); i++ { + if in[i] != '\r' { + buf = append(buf, in[i]) + } + } + out = string(buf) + } + // NOTE: Prior implementations did not verify that raw strings consist + // of valid UTF-8 characters and we continue to not verify it as such. + // The Go specification does not explicitly require valid UTF-8, + // but only mention that it is implicitly valid for Go source code + // (which must be valid UTF-8). + return out, in[end:], nil + case '"', '\'': + // Handle quoted strings without any escape sequences. + if !contains(in[:end], '\\') && !contains(in[:end], '\n') { + var valid bool + switch quote { + case '"': + valid = utf8.ValidString(in[len(`"`) : end-len(`"`)]) + case '\'': + r, n := utf8.DecodeRuneInString(in[len("'") : end-len("'")]) + valid = len("'")+n+len("'") == end && (r != utf8.RuneError || n != 1) + } + if valid { + out = in[:end] + if unescape { + out = out[1 : end-1] // exclude quotes + } + return out, in[end:], nil + } + } + + // Handle quoted strings with escape sequences. + var buf []byte + in0 := in + in = in[1:] // skip starting quote + if unescape { + buf = make([]byte, 0, 3*end/2) // try to avoid more allocations + } + for len(in) > 0 && in[0] != quote { + // Process the next character, + // rejecting any unescaped newline characters which are invalid. + r, multibyte, rem, err := UnquoteChar(in, quote) + if in[0] == '\n' || err != nil { + return "", in0, ErrSyntax + } + in = rem + + // Append the character if unescaping the input. + if unescape { + if r < utf8.RuneSelf || !multibyte { + buf = append(buf, byte(r)) + } else { + buf = utf8.AppendRune(buf, r) + } + } + + // Single quoted strings must be a single character. + if quote == '\'' { + break + } + } + + // Verify that the string ends with a terminating quote. + if !(len(in) > 0 && in[0] == quote) { + return "", in0, ErrSyntax + } + in = in[1:] // skip terminating quote + + if unescape { + return string(buf), in, nil + } + return in0[:len(in0)-len(in)], in, nil + default: + return "", in, ErrSyntax + } +} + +// bsearch16 returns the smallest i such that a[i] >= x. +// If there is no such i, bsearch16 returns len(a). +func bsearch16(a []uint16, x uint16) int { + i, j := 0, len(a) + for i < j { + h := i + (j-i)>>1 + if a[h] < x { + i = h + 1 + } else { + j = h + } + } + return i +} + +// bsearch32 returns the smallest i such that a[i] >= x. +// If there is no such i, bsearch32 returns len(a). +func bsearch32(a []uint32, x uint32) int { + i, j := 0, len(a) + for i < j { + h := i + (j-i)>>1 + if a[h] < x { + i = h + 1 + } else { + j = h + } + } + return i +} + +// TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests +// to give the same answer. It allows this package not to depend on unicode, +// and therefore not pull in all the Unicode tables. If the linker were better +// at tossing unused tables, we could get rid of this implementation. +// That would be nice. + +// IsPrint reports whether the rune is defined as printable by Go, with +// the same definition as unicode.IsPrint: letters, numbers, punctuation, +// symbols and ASCII space. +func IsPrint(r rune) bool { + // Fast check for Latin-1 + if r <= 0xFF { + if 0x20 <= r && r <= 0x7E { + // All the ASCII is printable from space through DEL-1. + return true + } + if 0xA1 <= r && r <= 0xFF { + // Similarly for ¡ through ÿ... + return r != 0xAD // ...except for the bizarre soft hyphen. + } + return false + } + + // Same algorithm, either on uint16 or uint32 value. + // First, find first i such that isPrint[i] >= x. + // This is the index of either the start or end of a pair that might span x. + // The start is even (isPrint[i&^1]) and the end is odd (isPrint[i|1]). + // If we find x in a range, make sure x is not in isNotPrint list. + + if 0 <= r && r < 1<<16 { + rr, isPrint, isNotPrint := uint16(r), isPrint16, isNotPrint16 + i := bsearch16(isPrint, rr) + if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { + return false + } + j := bsearch16(isNotPrint, rr) + return j >= len(isNotPrint) || isNotPrint[j] != rr + } + + rr, isPrint, isNotPrint := uint32(r), isPrint32, isNotPrint32 + i := bsearch32(isPrint, rr) + if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { + return false + } + if r >= 0x20000 { + return true + } + r -= 0x10000 + j := bsearch16(isNotPrint, uint16(r)) + return j >= len(isNotPrint) || isNotPrint[j] != uint16(r) +} + +// IsGraphic reports whether the rune is defined as a Graphic by Unicode. Such +// characters include letters, marks, numbers, punctuation, symbols, and +// spaces, from categories L, M, N, P, S, and Zs. +func IsGraphic(r rune) bool { + if IsPrint(r) { + return true + } + return isInGraphicList(r) +} + +// isInGraphicList reports whether the rune is in the isGraphic list. This separation +// from IsGraphic allows quoteWith to avoid two calls to IsPrint. +// Should be called only if IsPrint fails. +func isInGraphicList(r rune) bool { + // We know r must fit in 16 bits - see makeisprint.go. + if r > 0xFFFF { + return false + } + rr := uint16(r) + i := bsearch16(isGraphic, rr) + return i < len(isGraphic) && rr == isGraphic[i] +} diff --git a/gnovm/stdlibs/strconv/quote_test.gno b/gnovm/stdlibs/strconv/quote_test.gno new file mode 100644 index 00000000000..b11e95461b0 --- /dev/null +++ b/gnovm/stdlibs/strconv/quote_test.gno @@ -0,0 +1,383 @@ +// 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 strconv + +import ( + "strings" + "testing" + "unicode" +) + +// Verify that our IsPrint agrees with unicode.IsPrint. +func TestIsPrint(t *testing.T) { + n := 0 + for r := rune(0); r <= unicode.MaxRune; r++ { + if IsPrint(r) != unicode.IsPrint(r) { + t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r)) + n++ + if n > 10 { + return + } + } + } +} + +// Verify that our IsGraphic agrees with unicode.IsGraphic. +func TestIsGraphic(t *testing.T) { + n := 0 + for r := rune(0); r <= unicode.MaxRune; r++ { + if IsGraphic(r) != unicode.IsGraphic(r) { + t.Errorf("IsGraphic(%U)=%t incorrect", r, IsGraphic(r)) + n++ + if n > 10 { + return + } + } + } +} + +type quoteTest struct { + in string + out string + ascii string + graphic string +} + +var quotetests = []quoteTest{ + {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`}, + {"\\", `"\\"`, `"\\"`, `"\\"`}, + {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`, `"abc\xffdef"`}, + {"\u263a", `"☺"`, `"\u263a"`, `"☺"`}, + {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`, `"\U0010ffff"`}, + {"\x04", `"\x04"`, `"\x04"`, `"\x04"`}, + // Some non-printable but graphic runes. Final column is double-quoted. + {"!\u00a0!\u2000!\u3000!", `"!\u00a0!\u2000!\u3000!"`, `"!\u00a0!\u2000!\u3000!"`, "\"!\u00a0!\u2000!\u3000!\""}, + {"\x7f", `"\x7f"`, `"\x7f"`, `"\x7f"`}, +} + +func TestQuote(t *testing.T) { + for _, tt := range quotetests { + if out := Quote(tt.in); out != tt.out { + t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out) + } + if out := AppendQuote([]byte("abc"), tt.in); string(out) != "abc"+tt.out { + t.Errorf("AppendQuote(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.out) + } + } +} + +func TestQuoteToASCII(t *testing.T) { + for _, tt := range quotetests { + if out := QuoteToASCII(tt.in); out != tt.ascii { + t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii) + } + if out := AppendQuoteToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii { + t.Errorf("AppendQuoteToASCII(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii) + } + } +} + +func TestQuoteToGraphic(t *testing.T) { + for _, tt := range quotetests { + if out := QuoteToGraphic(tt.in); out != tt.graphic { + t.Errorf("QuoteToGraphic(%s) = %s, want %s", tt.in, out, tt.graphic) + } + if out := AppendQuoteToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic { + t.Errorf("AppendQuoteToGraphic(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic) + } + } +} + +func BenchmarkQuote(b *testing.B) { + for i := 0; i < b.N; i++ { + Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v") + } +} + +func BenchmarkQuoteRune(b *testing.B) { + for i := 0; i < b.N; i++ { + QuoteRune('\a') + } +} + +var benchQuoteBuf []byte + +func BenchmarkAppendQuote(b *testing.B) { + for i := 0; i < b.N; i++ { + benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v") + } +} + +var benchQuoteRuneBuf []byte + +func BenchmarkAppendQuoteRune(b *testing.B) { + for i := 0; i < b.N; i++ { + benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a') + } +} + +type quoteRuneTest struct { + in rune + out string + ascii string + graphic string +} + +var quoterunetests = []quoteRuneTest{ + {'a', `'a'`, `'a'`, `'a'`}, + {'\a', `'\a'`, `'\a'`, `'\a'`}, + {'\\', `'\\'`, `'\\'`, `'\\'`}, + {0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`}, + {0x263a, `'☺'`, `'\u263a'`, `'☺'`}, + {0xdead, `'�'`, `'\ufffd'`, `'�'`}, + {0xfffd, `'�'`, `'\ufffd'`, `'�'`}, + {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`}, + {0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`}, + {0x04, `'\x04'`, `'\x04'`, `'\x04'`}, + // Some differences between graphic and printable. Note the last column is double-quoted. + {'\u00a0', `'\u00a0'`, `'\u00a0'`, "'\u00a0'"}, + {'\u2000', `'\u2000'`, `'\u2000'`, "'\u2000'"}, + {'\u3000', `'\u3000'`, `'\u3000'`, "'\u3000'"}, +} + +func TestQuoteRune(t *testing.T) { + for _, tt := range quoterunetests { + if out := QuoteRune(tt.in); out != tt.out { + t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out) + } + if out := AppendQuoteRune([]byte("abc"), tt.in); string(out) != "abc"+tt.out { + t.Errorf("AppendQuoteRune(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.out) + } + } +} + +func TestQuoteRuneToASCII(t *testing.T) { + for _, tt := range quoterunetests { + if out := QuoteRuneToASCII(tt.in); out != tt.ascii { + t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii) + } + if out := AppendQuoteRuneToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii { + t.Errorf("AppendQuoteRuneToASCII(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii) + } + } +} + +func TestQuoteRuneToGraphic(t *testing.T) { + for _, tt := range quoterunetests { + if out := QuoteRuneToGraphic(tt.in); out != tt.graphic { + t.Errorf("QuoteRuneToGraphic(%U) = %s, want %s", tt.in, out, tt.graphic) + } + if out := AppendQuoteRuneToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic { + t.Errorf("AppendQuoteRuneToGraphic(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic) + } + } +} + +type canBackquoteTest struct { + in string + out bool +} + +var canbackquotetests = []canBackquoteTest{ + {"`", false}, + {string(rune(0)), false}, + {string(rune(1)), false}, + {string(rune(2)), false}, + {string(rune(3)), false}, + {string(rune(4)), false}, + {string(rune(5)), false}, + {string(rune(6)), false}, + {string(rune(7)), false}, + {string(rune(8)), false}, + {string(rune(9)), true}, // \t + {string(rune(10)), false}, + {string(rune(11)), false}, + {string(rune(12)), false}, + {string(rune(13)), false}, + {string(rune(14)), false}, + {string(rune(15)), false}, + {string(rune(16)), false}, + {string(rune(17)), false}, + {string(rune(18)), false}, + {string(rune(19)), false}, + {string(rune(20)), false}, + {string(rune(21)), false}, + {string(rune(22)), false}, + {string(rune(23)), false}, + {string(rune(24)), false}, + {string(rune(25)), false}, + {string(rune(26)), false}, + {string(rune(27)), false}, + {string(rune(28)), false}, + {string(rune(29)), false}, + {string(rune(30)), false}, + {string(rune(31)), false}, + {string(rune(0x7F)), false}, + {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true}, + {`0123456789`, true}, + {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true}, + {`abcdefghijklmnopqrstuvwxyz`, true}, + {`☺`, true}, + {"\x80", false}, + {"a\xe0\xa0z", false}, + {"\ufeffabc", false}, + {"a\ufeffz", false}, +} + +func TestCanBackquote(t *testing.T) { + for _, tt := range canbackquotetests { + if out := CanBackquote(tt.in); out != tt.out { + t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} + +type unQuoteTest struct { + in string + out string +} + +var unquotetests = []unQuoteTest{ + {`""`, ""}, + {`"a"`, "a"}, + {`"abc"`, "abc"}, + {`"☺"`, "☺"}, + {`"hello world"`, "hello world"}, + {`"\xFF"`, "\xFF"}, + {`"\377"`, "\377"}, + {`"\u1234"`, "\u1234"}, + {`"\U00010111"`, "\U00010111"}, + {`"\U0001011111"`, "\U0001011111"}, + {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""}, + {`"'"`, "'"}, + + {`'a'`, "a"}, + {`'☹'`, "☹"}, + {`'\a'`, "\a"}, + {`'\x10'`, "\x10"}, + {`'\377'`, "\377"}, + {`'\u1234'`, "\u1234"}, + {`'\U00010111'`, "\U00010111"}, + {`'\t'`, "\t"}, + {`' '`, " "}, + {`'\''`, "'"}, + {`'"'`, "\""}, + + {"``", ``}, + {"`a`", `a`}, + {"`abc`", `abc`}, + {"`☺`", `☺`}, + {"`hello world`", `hello world`}, + {"`\\xFF`", `\xFF`}, + {"`\\377`", `\377`}, + {"`\\`", `\`}, + {"`\n`", "\n"}, + {"` `", ` `}, + {"` `", ` `}, + {"`a\rb`", "ab"}, +} + +var misquoted = []string{ + ``, + `"`, + `"a`, + `"'`, + `b"`, + `"\"`, + `"\9"`, + `"\19"`, + `"\129"`, + `'\'`, + `'\9'`, + `'\19'`, + `'\129'`, + `'ab'`, + `"\x1!"`, + `"\U12345678"`, + `"\z"`, + "`", + "`xxx", + "``x\r", + "`\"", + `"\'"`, + `'\"'`, + "\"\n\"", + "\"\\n\n\"", + "'\n'", + `"\udead"`, + `"\ud83d\ude4f"`, +} + +func TestUnquote(t *testing.T) { + for _, tt := range unquotetests { + testUnquote(t, tt.in, tt.out, nil) + } + for _, tt := range quotetests { + testUnquote(t, tt.out, tt.in, nil) + } + for _, s := range misquoted { + testUnquote(t, s, "", ErrSyntax) + } +} + +// Issue 23685: invalid UTF-8 should not go through the fast path. +func TestUnquoteInvalidUTF8(t *testing.T) { + tests := []struct { + in string + + // one of: + want string + wantErr error + }{ + {in: `"foo"`, want: "foo"}, + {in: `"foo`, wantErr: ErrSyntax}, + {in: `"` + "\xc0" + `"`, want: "\xef\xbf\xbd"}, + {in: `"a` + "\xc0" + `"`, want: "a\xef\xbf\xbd"}, + {in: `"\t` + "\xc0" + `"`, want: "\t\xef\xbf\xbd"}, + } + for _, tt := range tests { + testUnquote(t, tt.in, tt.want, tt.wantErr) + } +} + +func testUnquote(t *testing.T, in, want string, wantErr error) { + // Test Unquote. + got, gotErr := Unquote(in) + if got != want || gotErr != wantErr { + t.Errorf("Unquote(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr) + } + + // Test QuotedPrefix. + // Adding an arbitrary suffix should not change the result of QuotedPrefix + // assume that the suffix doesn't accidentally terminate a truncated input. + if gotErr == nil { + want = in + } + suffix := "\n\r\\\"`'" // special characters for quoted strings + if len(in) > 0 { + suffix = strings.ReplaceAll(suffix, in[:1], "") + } + in += suffix + got, gotErr = QuotedPrefix(in) + if gotErr == nil && wantErr != nil { + _, wantErr = Unquote(got) // original input had trailing junk, reparse with only valid prefix + want = got + } + if got != want || gotErr != wantErr { + t.Errorf("QuotedPrefix(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr) + } +} + +func BenchmarkUnquoteEasy(b *testing.B) { + for i := 0; i < b.N; i++ { + Unquote(`"Give me a rock, paper and scissors and I will move the world."`) + } +} + +func BenchmarkUnquoteHard(b *testing.B) { + for i := 0; i < b.N; i++ { + Unquote(`"\x47ive me a \x72ock, \x70aper and \x73cissors and \x49 will move the world."`) + } +} diff --git a/gnovm/stdlibs/strconv/strconv.gno b/gnovm/stdlibs/strconv/strconv.gno deleted file mode 100644 index bc7b5d8d1b6..00000000000 --- a/gnovm/stdlibs/strconv/strconv.gno +++ /dev/null @@ -1,10 +0,0 @@ -package strconv - -func Itoa(n int) string // injected -func AppendUint(dst []byte, i uint64, base int) []byte // injected -func Atoi(s string) (int, error) // injected -func CanBackquote(s string) bool // injected -func FormatInt(i int64, base int) string // injected -func FormatUint(i uint64, base int) string // injected -func Quote(s string) string // injected -func QuoteToASCII(s string) string // injected diff --git a/gnovm/stdlibs/strconv/strconv.go b/gnovm/stdlibs/strconv/strconv.go deleted file mode 100644 index 782a63e84b6..00000000000 --- a/gnovm/stdlibs/strconv/strconv.go +++ /dev/null @@ -1,12 +0,0 @@ -package strconv - -import "strconv" - -func Itoa(n int) string { return strconv.Itoa(n) } -func AppendUint(dst []byte, i uint64, base int) []byte { return strconv.AppendUint(dst, i, base) } -func Atoi(s string) (int, error) { return strconv.Atoi(s) } -func CanBackquote(s string) bool { return strconv.CanBackquote(s) } -func FormatInt(i int64, base int) string { return strconv.FormatInt(i, base) } -func FormatUint(i uint64, base int) string { return strconv.FormatUint(i, base) } -func Quote(s string) string { return strconv.Quote(s) } -func QuoteToASCII(r string) string { return strconv.QuoteToASCII(r) } diff --git a/gnovm/stdlibs/strconv/strconv_test.gno b/gnovm/stdlibs/strconv/strconv_test.gno new file mode 100644 index 00000000000..5421ae84a93 --- /dev/null +++ b/gnovm/stdlibs/strconv/strconv_test.gno @@ -0,0 +1,156 @@ +// Copyright 2012 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 strconv + +import ( + "strings" + "testing" +) + +var ( + globalBuf [64]byte + nextToOne = "1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1" + oneMB = make([]byte, 1e6) + + mallocTest = []struct { + count int + desc string + fn func() + }{ + {0, `AppendInt(localBuf[:0], 123, 10)`, func() { + var localBuf [64]byte + AppendInt(localBuf[:0], 123, 10) + }}, + {0, `AppendInt(globalBuf[:0], 123, 10)`, func() { AppendInt(globalBuf[:0], 123, 10) }}, + {0, `AppendFloat(localBuf[:0], 1.23, 'g', 5, 64)`, func() { + var localBuf [64]byte + AppendFloat(localBuf[:0], 1.23, 'g', 5, 64) + }}, + {0, `AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64)`, func() { AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64) }}, + // In practice we see 7 for the next one, but allow some slop. + // Before pre-allocation in appendQuotedWith, we saw 39. + {10, `AppendQuoteToASCII(nil, oneMB)`, func() { AppendQuoteToASCII(nil, string(oneMB)) }}, + {0, `ParseFloat("123.45", 64)`, func() { ParseFloat("123.45", 64) }}, + {0, `ParseFloat("123.456789123456789", 64)`, func() { ParseFloat("123.456789123456789", 64) }}, + {0, `ParseFloat("1.000000000000000111022302462515654042363166809082031251", 64)`, func() { + ParseFloat("1.000000000000000111022302462515654042363166809082031251", 64) + }}, + {0, `ParseFloat("1.0000000000000001110223024625156540423631668090820312500...001", 64)`, func() { + ParseFloat(nextToOne, 64) + }}, + } +) + +// XXX: removed due to lack of AllocsPerRun +// func TestCountMallocs(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping malloc count in short mode") +// } +// // Allocate a big messy buffer for AppendQuoteToASCII's test. +// oneMB = make([]byte, 1e6) +// for i := range oneMB { +// oneMB[i] = byte(i) +// } +// for _, mt := range mallocTest { +// allocs := testing.AllocsPerRun(100, mt.fn) +// if max := float64(mt.count); allocs > max { +// t.Errorf("%s: %v allocs, want <=%v", mt.desc, allocs, max) +// } +// } +// } + +// Sink makes sure the compiler cannot optimize away the benchmarks. +var Sink struct { + Bool bool + Int int + Int64 int64 + Uint64 uint64 + Float64 float64 + Error error + Bytes []byte +} + +/* XXX: removed due to lack of AllocsPerRun +func TestAllocationsFromBytes(t *testing.T) { + const runsPerTest = 100 + bytes := struct{ Bool, Number, String, Buffer []byte }{ + Bool: []byte("false"), + Number: []byte("123456789"), + String: []byte("hello, world!"), + Buffer: make([]byte, 1024), + } + + checkNoAllocs := func(f func()) func(t *testing.T) { + return func(t *testing.T) { + t.Helper() + if allocs := testing.AllocsPerRun(runsPerTest, f); allocs != 0 { + t.Errorf("got %v allocs, want 0 allocs", allocs) + } + } + } + + t.Run("Atoi", checkNoAllocs(func() { + Sink.Int, Sink.Error = Atoi(string(bytes.Number)) + })) + t.Run("ParseBool", checkNoAllocs(func() { + Sink.Bool, Sink.Error = ParseBool(string(bytes.Bool)) + })) + t.Run("ParseInt", checkNoAllocs(func() { + Sink.Int64, Sink.Error = ParseInt(string(bytes.Number), 10, 64) + })) + t.Run("ParseUint", checkNoAllocs(func() { + Sink.Uint64, Sink.Error = ParseUint(string(bytes.Number), 10, 64) + })) + t.Run("ParseFloat", checkNoAllocs(func() { + Sink.Float64, Sink.Error = ParseFloat(string(bytes.Number), 64) + })) + t.Run("ParseComplex", checkNoAllocs(func() { + Sink.Complex128, Sink.Error = ParseComplex(string(bytes.Number), 128) + })) + t.Run("CanBackquote", checkNoAllocs(func() { + Sink.Bool = CanBackquote(string(bytes.String)) + })) + t.Run("AppendQuote", checkNoAllocs(func() { + Sink.Bytes = AppendQuote(bytes.Buffer[:0], string(bytes.String)) + })) + t.Run("AppendQuoteToASCII", checkNoAllocs(func() { + Sink.Bytes = AppendQuoteToASCII(bytes.Buffer[:0], string(bytes.String)) + })) + t.Run("AppendQuoteToGraphic", checkNoAllocs(func() { + Sink.Bytes = AppendQuoteToGraphic(bytes.Buffer[:0], string(bytes.String)) + })) +} +*/ + +func TestErrorPrefixes(t *testing.T) { + _, errInt := Atoi("INVALID") + _, errBool := ParseBool("INVALID") + _, errFloat := ParseFloat("INVALID", 64) + _, errInt64 := ParseInt("INVALID", 10, 64) + _, errUint64 := ParseUint("INVALID", 10, 64) + + vectors := []struct { + err error // Input error + want string // Function name wanted + }{ + {errInt, "Atoi"}, + {errBool, "ParseBool"}, + {errFloat, "ParseFloat"}, + {errInt64, "ParseInt"}, + {errUint64, "ParseUint"}, + } + + for _, v := range vectors { + nerr, ok := v.err.(*NumError) + if !ok { + t.Errorf("test %s, error was not a *NumError", v.want) + continue + } + if got := nerr.Func; got != v.want { + t.Errorf("mismatching Func: got %s, want %s", got, v.want) + } + } + +} diff --git a/gnovm/stdlibs/unicode/example_test.gno b/gnovm/stdlibs/unicode/example_test.gno index 3ab11a4b5d2..bd2920dfb56 100644 --- a/gnovm/stdlibs/unicode/example_test.gno +++ b/gnovm/stdlibs/unicode/example_test.gno @@ -116,7 +116,7 @@ func ExampleSimpleFold() { fmt.Printf("%#U\n", unicode.SimpleFold('A')) // 'a' fmt.Printf("%#U\n", unicode.SimpleFold('a')) // 'A' fmt.Printf("%#U\n", unicode.SimpleFold('K')) // 'k' - fmt.Printf("%#U\n", unicode.SimpleFold('k')) // '\u212A' (Kelvin symbol, K) + fmt.Printf("%#U\n", unicode.SimpleFold('k')) // '\u212A' (Kelvin symbol, K) fmt.Printf("%#U\n", unicode.SimpleFold('\u212A')) // 'K' fmt.Printf("%#U\n", unicode.SimpleFold('1')) // '1' @@ -124,7 +124,7 @@ func ExampleSimpleFold() { // U+0061 'a' // U+0041 'A' // U+006B 'k' - // U+212A 'K' + // U+212A 'K' // U+004B 'K' // U+0031 '1' } @@ -194,3 +194,63 @@ func ExampleSpecialCase() { // U+0130 'İ' // U+0130 'İ' } + +func ExampleIsDigit() { + fmt.Printf("%t\n", unicode.IsDigit('৩')) + fmt.Printf("%t\n", unicode.IsDigit('A')) + // Output: + // true + // false +} + +func ExampleIsNumber() { + fmt.Printf("%t\n", unicode.IsNumber('Ⅷ')) + fmt.Printf("%t\n", unicode.IsNumber('A')) + // Output: + // true + // false +} + +func ExampleIsLetter() { + fmt.Printf("%t\n", unicode.IsLetter('A')) + fmt.Printf("%t\n", unicode.IsLetter('7')) + // Output: + // true + // false +} + +func ExampleIsLower() { + fmt.Printf("%t\n", unicode.IsLower('a')) + fmt.Printf("%t\n", unicode.IsLower('A')) + // Output: + // true + // false +} + +func ExampleIsUpper() { + fmt.Printf("%t\n", unicode.IsUpper('A')) + fmt.Printf("%t\n", unicode.IsUpper('a')) + // Output: + // true + // false +} + +func ExampleIsTitle() { + fmt.Printf("%t\n", unicode.IsTitle('Dž')) + fmt.Printf("%t\n", unicode.IsTitle('a')) + // Output: + // true + // false +} + +func ExampleIsSpace() { + fmt.Printf("%t\n", unicode.IsSpace(' ')) + fmt.Printf("%t\n", unicode.IsSpace('\n')) + fmt.Printf("%t\n", unicode.IsSpace('\t')) + fmt.Printf("%t\n", unicode.IsSpace('a')) + // Output: + // true + // true + // true + // false +} diff --git a/gnovm/stdlibs/unicode/letter.gno b/gnovm/stdlibs/unicode/letter.gno index aa1039aa38d..f3f8e529648 100644 --- a/gnovm/stdlibs/unicode/letter.gno +++ b/gnovm/stdlibs/unicode/letter.gno @@ -331,7 +331,7 @@ type foldPair struct { // SimpleFold('a') = 'A' // // SimpleFold('K') = 'k' -// SimpleFold('k') = '\u212A' (Kelvin symbol, K) +// SimpleFold('k') = '\u212A' (Kelvin symbol, K) // SimpleFold('\u212A') = 'K' // // SimpleFold('1') = '1' diff --git a/gnovm/stdlibs/unicode/tables.gno b/gnovm/stdlibs/unicode/tables.gno index a57e0ca67cb..b3d65d9d5c1 100644 --- a/gnovm/stdlibs/unicode/tables.gno +++ b/gnovm/stdlibs/unicode/tables.gno @@ -3,7 +3,7 @@ package unicode // Version is the Unicode edition from which the tables are derived. -const Version = "13.0.0" +const Version = "15.0.0" // Categories is the set of Unicode category tables. var Categories = map[string]*RangeTable{ @@ -52,7 +52,8 @@ var _C = &RangeTable{ {0x00ad, 0x0600, 1363}, {0x0601, 0x0605, 1}, {0x061c, 0x06dd, 193}, - {0x070f, 0x08e2, 467}, + {0x070f, 0x0890, 385}, + {0x0891, 0x08e2, 81}, {0x180e, 0x200b, 2045}, {0x200c, 0x200f, 1}, {0x202a, 0x202e, 1}, @@ -64,7 +65,7 @@ var _C = &RangeTable{ }, R32: []Range32{ {0x110bd, 0x110cd, 16}, - {0x13430, 0x13438, 1}, + {0x13430, 0x1343f, 1}, {0x1bca0, 0x1bca3, 1}, {0x1d173, 0x1d17a, 1}, {0xe0001, 0xe0020, 31}, @@ -88,7 +89,8 @@ var _Cf = &RangeTable{ {0x00ad, 0x0600, 1363}, {0x0601, 0x0605, 1}, {0x061c, 0x06dd, 193}, - {0x070f, 0x08e2, 467}, + {0x070f, 0x0890, 385}, + {0x0891, 0x08e2, 81}, {0x180e, 0x200b, 2045}, {0x200c, 0x200f, 1}, {0x202a, 0x202e, 1}, @@ -99,7 +101,7 @@ var _Cf = &RangeTable{ }, R32: []Range32{ {0x110bd, 0x110cd, 16}, - {0x13430, 0x13438, 1}, + {0x13430, 0x1343f, 1}, {0x1bca0, 0x1bca3, 1}, {0x1d173, 0x1d17a, 1}, {0xe0001, 0xe0020, 31}, @@ -169,8 +171,9 @@ var _L = &RangeTable{ {0x0828, 0x0840, 24}, {0x0841, 0x0858, 1}, {0x0860, 0x086a, 1}, - {0x08a0, 0x08b4, 1}, - {0x08b6, 0x08c7, 1}, + {0x0870, 0x0887, 1}, + {0x0889, 0x088e, 1}, + {0x08a0, 0x08c9, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, @@ -231,17 +234,18 @@ var _L = &RangeTable{ {0x0c2a, 0x0c39, 1}, {0x0c3d, 0x0c58, 27}, {0x0c59, 0x0c5a, 1}, - {0x0c60, 0x0c61, 1}, - {0x0c80, 0x0c85, 5}, - {0x0c86, 0x0c8c, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c80, 31}, + {0x0c85, 0x0c8c, 1}, {0x0c8e, 0x0c90, 1}, {0x0c92, 0x0ca8, 1}, {0x0caa, 0x0cb3, 1}, {0x0cb5, 0x0cb9, 1}, - {0x0cbd, 0x0cde, 33}, - {0x0ce0, 0x0ce1, 1}, - {0x0cf1, 0x0cf2, 1}, - {0x0d04, 0x0d0c, 1}, + {0x0cbd, 0x0cdd, 32}, + {0x0cde, 0x0ce0, 2}, + {0x0ce1, 0x0cf1, 16}, + {0x0cf2, 0x0d04, 18}, + {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, {0x0d12, 0x0d3a, 1}, {0x0d3d, 0x0d4e, 17}, @@ -307,9 +311,8 @@ var _L = &RangeTable{ {0x1681, 0x169a, 1}, {0x16a0, 0x16ea, 1}, {0x16f1, 0x16f8, 1}, - {0x1700, 0x170c, 1}, - {0x170e, 0x1711, 1}, - {0x1720, 0x1731, 1}, + {0x1700, 0x1711, 1}, + {0x171f, 0x1731, 1}, {0x1740, 0x1751, 1}, {0x1760, 0x176c, 1}, {0x176e, 0x1770, 1}, @@ -329,7 +332,7 @@ var _L = &RangeTable{ {0x1a20, 0x1a54, 1}, {0x1aa7, 0x1b05, 94}, {0x1b06, 0x1b33, 1}, - {0x1b45, 0x1b4b, 1}, + {0x1b45, 0x1b4c, 1}, {0x1b83, 0x1ba0, 1}, {0x1bae, 0x1baf, 1}, {0x1bba, 0x1be5, 1}, @@ -374,9 +377,7 @@ var _L = &RangeTable{ {0x2145, 0x2149, 1}, {0x214e, 0x2183, 53}, {0x2184, 0x2c00, 2684}, - {0x2c01, 0x2c2e, 1}, - {0x2c30, 0x2c5e, 1}, - {0x2c60, 0x2ce4, 1}, + {0x2c01, 0x2ce4, 1}, {0x2ceb, 0x2cee, 1}, {0x2cf2, 0x2cf3, 1}, {0x2d00, 0x2d25, 1}, @@ -405,8 +406,7 @@ var _L = &RangeTable{ {0x31a0, 0x31bf, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, - {0xa000, 0xa48c, 1}, + {0x4e00, 0xa48c, 1}, {0xa4d0, 0xa4fd, 1}, {0xa500, 0xa60c, 1}, {0xa610, 0xa61f, 1}, @@ -416,9 +416,11 @@ var _L = &RangeTable{ {0xa6a0, 0xa6e5, 1}, {0xa717, 0xa71f, 1}, {0xa722, 0xa788, 1}, - {0xa78b, 0xa7bf, 1}, - {0xa7c2, 0xa7ca, 1}, - {0xa7f5, 0xa801, 1}, + {0xa78b, 0xa7ca, 1}, + {0xa7d0, 0xa7d1, 1}, + {0xa7d3, 0xa7d5, 2}, + {0xa7d6, 0xa7d9, 1}, + {0xa7f2, 0xa801, 1}, {0xa803, 0xa805, 1}, {0xa807, 0xa80a, 1}, {0xa80c, 0xa822, 1}, @@ -507,9 +509,20 @@ var _L = &RangeTable{ {0x104d8, 0x104fb, 1}, {0x10500, 0x10527, 1}, {0x10530, 0x10563, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, {0x10600, 0x10736, 1}, {0x10740, 0x10755, 1}, {0x10760, 0x10767, 1}, + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, {0x10800, 0x10805, 1}, {0x10808, 0x1080a, 2}, {0x1080b, 0x10835, 1}, @@ -545,10 +558,13 @@ var _L = &RangeTable{ {0x10f00, 0x10f1c, 1}, {0x10f27, 0x10f30, 9}, {0x10f31, 0x10f45, 1}, + {0x10f70, 0x10f81, 1}, {0x10fb0, 0x10fc4, 1}, {0x10fe0, 0x10ff6, 1}, {0x11003, 0x11037, 1}, - {0x11083, 0x110af, 1}, + {0x11071, 0x11072, 1}, + {0x11075, 0x11083, 14}, + {0x11084, 0x110af, 1}, {0x110d0, 0x110e8, 1}, {0x11103, 0x11126, 1}, {0x11144, 0x11147, 3}, @@ -559,6 +575,7 @@ var _L = &RangeTable{ {0x111da, 0x111dc, 2}, {0x11200, 0x11211, 1}, {0x11213, 0x1122b, 1}, + {0x1123f, 0x11240, 1}, {0x11280, 0x11286, 1}, {0x11288, 0x1128a, 2}, {0x1128b, 0x1128d, 1}, @@ -586,6 +603,7 @@ var _L = &RangeTable{ {0x11681, 0x116aa, 1}, {0x116b8, 0x11700, 72}, {0x11701, 0x1171a, 1}, + {0x11740, 0x11746, 1}, {0x11800, 0x1182b, 1}, {0x118a0, 0x118df, 1}, {0x118ff, 0x11906, 1}, @@ -601,8 +619,8 @@ var _L = &RangeTable{ {0x11a0c, 0x11a32, 1}, {0x11a3a, 0x11a50, 22}, {0x11a5c, 0x11a89, 1}, - {0x11a9d, 0x11ac0, 35}, - {0x11ac1, 0x11af8, 1}, + {0x11a9d, 0x11ab0, 19}, + {0x11ab1, 0x11af8, 1}, {0x11c00, 0x11c08, 1}, {0x11c0a, 0x11c2e, 1}, {0x11c40, 0x11c72, 50}, @@ -616,13 +634,19 @@ var _L = &RangeTable{ {0x11d6a, 0x11d89, 1}, {0x11d98, 0x11ee0, 328}, {0x11ee1, 0x11ef2, 1}, + {0x11f02, 0x11f04, 2}, + {0x11f05, 0x11f10, 1}, + {0x11f12, 0x11f33, 1}, {0x11fb0, 0x12000, 80}, {0x12001, 0x12399, 1}, {0x12480, 0x12543, 1}, - {0x13000, 0x1342e, 1}, + {0x12f90, 0x12ff0, 1}, + {0x13000, 0x1342f, 1}, + {0x13441, 0x13446, 1}, {0x14400, 0x14646, 1}, {0x16800, 0x16a38, 1}, {0x16a40, 0x16a5e, 1}, + {0x16a70, 0x16abe, 1}, {0x16ad0, 0x16aed, 1}, {0x16b00, 0x16b2f, 1}, {0x16b40, 0x16b43, 1}, @@ -637,9 +661,14 @@ var _L = &RangeTable{ {0x17001, 0x187f7, 1}, {0x18800, 0x18cd5, 1}, {0x18d00, 0x18d08, 1}, - {0x1b000, 0x1b11e, 1}, - {0x1b150, 0x1b152, 1}, - {0x1b164, 0x1b167, 1}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1b000, 0x1b122, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, {0x1b170, 0x1b2fb, 1}, {0x1bc00, 0x1bc6a, 1}, {0x1bc70, 0x1bc7c, 1}, @@ -675,10 +704,19 @@ var _L = &RangeTable{ {0x1d78a, 0x1d7a8, 1}, {0x1d7aa, 0x1d7c2, 1}, {0x1d7c4, 0x1d7cb, 1}, + {0x1df00, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + {0x1e030, 0x1e06d, 1}, {0x1e100, 0x1e12c, 1}, {0x1e137, 0x1e13d, 1}, - {0x1e14e, 0x1e2c0, 370}, - {0x1e2c1, 0x1e2eb, 1}, + {0x1e14e, 0x1e290, 322}, + {0x1e291, 0x1e2ad, 1}, + {0x1e2c0, 0x1e2eb, 1}, + {0x1e4d0, 0x1e4eb, 1}, + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, {0x1e800, 0x1e8c4, 1}, {0x1e900, 0x1e943, 1}, {0x1e94b, 0x1ee00, 1205}, @@ -706,13 +744,14 @@ var _L = &RangeTable{ {0x1eea1, 0x1eea3, 1}, {0x1eea5, 0x1eea9, 1}, {0x1eeab, 0x1eebb, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, LatinOffset: 6, } @@ -807,7 +846,7 @@ var _Ll = &RangeTable{ {0x213c, 0x213d, 1}, {0x2146, 0x2149, 1}, {0x214e, 0x2184, 54}, - {0x2c30, 0x2c5e, 1}, + {0x2c30, 0x2c5f, 1}, {0x2c61, 0x2c65, 4}, {0x2c66, 0x2c6c, 2}, {0x2c71, 0x2c73, 2}, @@ -831,11 +870,11 @@ var _Ll = &RangeTable{ {0xa794, 0xa795, 1}, {0xa797, 0xa7a9, 2}, {0xa7af, 0xa7b5, 6}, - {0xa7b7, 0xa7bf, 2}, - {0xa7c3, 0xa7c8, 5}, - {0xa7ca, 0xa7f6, 44}, - {0xa7fa, 0xab30, 822}, - {0xab31, 0xab5a, 1}, + {0xa7b7, 0xa7c3, 2}, + {0xa7c8, 0xa7ca, 2}, + {0xa7d1, 0xa7d9, 2}, + {0xa7f6, 0xa7fa, 4}, + {0xab30, 0xab5a, 1}, {0xab60, 0xab68, 1}, {0xab70, 0xabbf, 1}, {0xfb00, 0xfb06, 1}, @@ -845,6 +884,10 @@ var _Ll = &RangeTable{ R32: []Range32{ {0x10428, 0x1044f, 1}, {0x104d8, 0x104fb, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, {0x10cc0, 0x10cf2, 1}, {0x118c0, 0x118df, 1}, {0x16e60, 0x16e7f, 1}, @@ -875,8 +918,11 @@ var _Ll = &RangeTable{ {0x1d78a, 0x1d78f, 1}, {0x1d7aa, 0x1d7c2, 1}, {0x1d7c4, 0x1d7c9, 1}, - {0x1d7cb, 0x1e922, 4439}, - {0x1e923, 0x1e943, 1}, + {0x1d7cb, 0x1df00, 1845}, + {0x1df01, 0x1df09, 1}, + {0x1df0b, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + {0x1e922, 0x1e943, 1}, }, LatinOffset: 4, } @@ -893,11 +939,11 @@ var _Lm = &RangeTable{ {0x07f4, 0x07f5, 1}, {0x07fa, 0x081a, 32}, {0x0824, 0x0828, 4}, - {0x0971, 0x0e46, 1237}, - {0x0ec6, 0x10fc, 566}, - {0x17d7, 0x1843, 108}, - {0x1aa7, 0x1c78, 465}, - {0x1c79, 0x1c7d, 1}, + {0x08c9, 0x0971, 168}, + {0x0e46, 0x0ec6, 128}, + {0x10fc, 0x17d7, 1755}, + {0x1843, 0x1aa7, 612}, + {0x1c78, 0x1c7d, 1}, {0x1d2c, 0x1d6a, 1}, {0x1d78, 0x1d9b, 35}, {0x1d9c, 0x1dbf, 1}, @@ -916,6 +962,7 @@ var _Lm = &RangeTable{ {0xa69c, 0xa69d, 1}, {0xa717, 0xa71f, 1}, {0xa770, 0xa788, 24}, + {0xa7f2, 0xa7f4, 1}, {0xa7f8, 0xa7f9, 1}, {0xa9cf, 0xa9e6, 23}, {0xaa70, 0xaadd, 109}, @@ -925,12 +972,19 @@ var _Lm = &RangeTable{ {0xff9e, 0xff9f, 1}, }, R32: []Range32{ + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, {0x16b40, 0x16b43, 1}, {0x16f93, 0x16f9f, 1}, {0x16fe0, 0x16fe1, 1}, - {0x16fe3, 0x1e137, 29012}, - {0x1e138, 0x1e13d, 1}, - {0x1e94b, 0x1e94b, 1}, + {0x16fe3, 0x1aff0, 16397}, + {0x1aff1, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1e030, 0x1e06d, 1}, + {0x1e137, 0x1e13d, 1}, + {0x1e4eb, 0x1e94b, 1120}, }, } @@ -957,8 +1011,9 @@ var _Lo = &RangeTable{ {0x0800, 0x0815, 1}, {0x0840, 0x0858, 1}, {0x0860, 0x086a, 1}, - {0x08a0, 0x08b4, 1}, - {0x08b6, 0x08c7, 1}, + {0x0870, 0x0887, 1}, + {0x0889, 0x088e, 1}, + {0x08a0, 0x08c8, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, @@ -1019,17 +1074,18 @@ var _Lo = &RangeTable{ {0x0c2a, 0x0c39, 1}, {0x0c3d, 0x0c58, 27}, {0x0c59, 0x0c5a, 1}, - {0x0c60, 0x0c61, 1}, - {0x0c80, 0x0c85, 5}, - {0x0c86, 0x0c8c, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c80, 31}, + {0x0c85, 0x0c8c, 1}, {0x0c8e, 0x0c90, 1}, {0x0c92, 0x0ca8, 1}, {0x0caa, 0x0cb3, 1}, {0x0cb5, 0x0cb9, 1}, - {0x0cbd, 0x0cde, 33}, - {0x0ce0, 0x0ce1, 1}, - {0x0cf1, 0x0cf2, 1}, - {0x0d04, 0x0d0c, 1}, + {0x0cbd, 0x0cdd, 32}, + {0x0cde, 0x0ce0, 2}, + {0x0ce1, 0x0cf1, 16}, + {0x0cf2, 0x0d04, 18}, + {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, {0x0d12, 0x0d3a, 1}, {0x0d3d, 0x0d4e, 17}, @@ -1089,9 +1145,8 @@ var _Lo = &RangeTable{ {0x1681, 0x169a, 1}, {0x16a0, 0x16ea, 1}, {0x16f1, 0x16f8, 1}, - {0x1700, 0x170c, 1}, - {0x170e, 0x1711, 1}, - {0x1720, 0x1731, 1}, + {0x1700, 0x1711, 1}, + {0x171f, 0x1731, 1}, {0x1740, 0x1751, 1}, {0x1760, 0x176c, 1}, {0x176e, 0x1770, 1}, @@ -1111,7 +1166,7 @@ var _Lo = &RangeTable{ {0x1a00, 0x1a16, 1}, {0x1a20, 0x1a54, 1}, {0x1b05, 0x1b33, 1}, - {0x1b45, 0x1b4b, 1}, + {0x1b45, 0x1b4c, 1}, {0x1b83, 0x1ba0, 1}, {0x1bae, 0x1baf, 1}, {0x1bba, 0x1be5, 1}, @@ -1143,8 +1198,7 @@ var _Lo = &RangeTable{ {0x31a0, 0x31bf, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, - {0xa000, 0xa014, 1}, + {0x4e00, 0xa014, 1}, {0xa016, 0xa48c, 1}, {0xa4d0, 0xa4f7, 1}, {0xa500, 0xa60b, 1}, @@ -1272,10 +1326,13 @@ var _Lo = &RangeTable{ {0x10f00, 0x10f1c, 1}, {0x10f27, 0x10f30, 9}, {0x10f31, 0x10f45, 1}, + {0x10f70, 0x10f81, 1}, {0x10fb0, 0x10fc4, 1}, {0x10fe0, 0x10ff6, 1}, {0x11003, 0x11037, 1}, - {0x11083, 0x110af, 1}, + {0x11071, 0x11072, 1}, + {0x11075, 0x11083, 14}, + {0x11084, 0x110af, 1}, {0x110d0, 0x110e8, 1}, {0x11103, 0x11126, 1}, {0x11144, 0x11147, 3}, @@ -1286,6 +1343,7 @@ var _Lo = &RangeTable{ {0x111da, 0x111dc, 2}, {0x11200, 0x11211, 1}, {0x11213, 0x1122b, 1}, + {0x1123f, 0x11240, 1}, {0x11280, 0x11286, 1}, {0x11288, 0x1128a, 2}, {0x1128b, 0x1128d, 1}, @@ -1313,6 +1371,7 @@ var _Lo = &RangeTable{ {0x11681, 0x116aa, 1}, {0x116b8, 0x11700, 72}, {0x11701, 0x1171a, 1}, + {0x11740, 0x11746, 1}, {0x11800, 0x1182b, 1}, {0x118ff, 0x11906, 1}, {0x11909, 0x1190c, 3}, @@ -1327,8 +1386,8 @@ var _Lo = &RangeTable{ {0x11a0c, 0x11a32, 1}, {0x11a3a, 0x11a50, 22}, {0x11a5c, 0x11a89, 1}, - {0x11a9d, 0x11ac0, 35}, - {0x11ac1, 0x11af8, 1}, + {0x11a9d, 0x11ab0, 19}, + {0x11ab1, 0x11af8, 1}, {0x11c00, 0x11c08, 1}, {0x11c0a, 0x11c2e, 1}, {0x11c40, 0x11c72, 50}, @@ -1342,13 +1401,19 @@ var _Lo = &RangeTable{ {0x11d6a, 0x11d89, 1}, {0x11d98, 0x11ee0, 328}, {0x11ee1, 0x11ef2, 1}, + {0x11f02, 0x11f04, 2}, + {0x11f05, 0x11f10, 1}, + {0x11f12, 0x11f33, 1}, {0x11fb0, 0x12000, 80}, {0x12001, 0x12399, 1}, {0x12480, 0x12543, 1}, - {0x13000, 0x1342e, 1}, + {0x12f90, 0x12ff0, 1}, + {0x13000, 0x1342f, 1}, + {0x13441, 0x13446, 1}, {0x14400, 0x14646, 1}, {0x16800, 0x16a38, 1}, {0x16a40, 0x16a5e, 1}, + {0x16a70, 0x16abe, 1}, {0x16ad0, 0x16aed, 1}, {0x16b00, 0x16b2f, 1}, {0x16b63, 0x16b77, 1}, @@ -1358,17 +1423,26 @@ var _Lo = &RangeTable{ {0x17001, 0x187f7, 1}, {0x18800, 0x18cd5, 1}, {0x18d00, 0x18d08, 1}, - {0x1b000, 0x1b11e, 1}, - {0x1b150, 0x1b152, 1}, - {0x1b164, 0x1b167, 1}, + {0x1b000, 0x1b122, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, {0x1b170, 0x1b2fb, 1}, {0x1bc00, 0x1bc6a, 1}, {0x1bc70, 0x1bc7c, 1}, {0x1bc80, 0x1bc88, 1}, {0x1bc90, 0x1bc99, 1}, - {0x1e100, 0x1e12c, 1}, - {0x1e14e, 0x1e2c0, 370}, - {0x1e2c1, 0x1e2eb, 1}, + {0x1df0a, 0x1e100, 502}, + {0x1e101, 0x1e12c, 1}, + {0x1e14e, 0x1e290, 322}, + {0x1e291, 0x1e2ad, 1}, + {0x1e2c0, 0x1e2eb, 1}, + {0x1e4d0, 0x1e4ea, 1}, + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, {0x1e800, 0x1e8c4, 1}, {0x1ee00, 0x1ee03, 1}, {0x1ee05, 0x1ee1f, 1}, @@ -1394,13 +1468,14 @@ var _Lo = &RangeTable{ {0x1eea1, 0x1eea3, 1}, {0x1eea5, 0x1eea9, 1}, {0x1eeab, 0x1eebb, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, LatinOffset: 1, } @@ -1501,7 +1576,7 @@ var _Lu = &RangeTable{ {0x2130, 0x2133, 1}, {0x213e, 0x213f, 1}, {0x2145, 0x2183, 62}, - {0x2c00, 0x2c2e, 1}, + {0x2c00, 0x2c2f, 1}, {0x2c60, 0x2c62, 2}, {0x2c63, 0x2c64, 1}, {0x2c67, 0x2c6d, 2}, @@ -1522,15 +1597,20 @@ var _Lu = &RangeTable{ {0xa796, 0xa7aa, 2}, {0xa7ab, 0xa7ae, 1}, {0xa7b0, 0xa7b4, 1}, - {0xa7b6, 0xa7be, 2}, - {0xa7c2, 0xa7c4, 2}, + {0xa7b6, 0xa7c4, 2}, {0xa7c5, 0xa7c7, 1}, - {0xa7c9, 0xa7f5, 44}, - {0xff21, 0xff3a, 1}, + {0xa7c9, 0xa7d0, 7}, + {0xa7d6, 0xa7d8, 2}, + {0xa7f5, 0xff21, 22316}, + {0xff22, 0xff3a, 1}, }, R32: []Range32{ {0x10400, 0x10427, 1}, {0x104b0, 0x104d3, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, {0x10c80, 0x10cb2, 1}, {0x118a0, 0x118bf, 1}, {0x16e40, 0x16e5f, 1}, @@ -1594,7 +1674,8 @@ var _M = &RangeTable{ {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, {0x0859, 0x085b, 1}, - {0x08d3, 0x08e1, 1}, + {0x0898, 0x089f, 1}, + {0x08ca, 0x08e1, 1}, {0x08e3, 0x0903, 1}, {0x093a, 0x093c, 1}, {0x093e, 0x094f, 1}, @@ -1634,7 +1715,8 @@ var _M = &RangeTable{ {0x0bca, 0x0bcd, 1}, {0x0bd7, 0x0c00, 41}, {0x0c01, 0x0c04, 1}, - {0x0c3e, 0x0c44, 1}, + {0x0c3c, 0x0c3e, 2}, + {0x0c3f, 0x0c44, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, @@ -1646,7 +1728,8 @@ var _M = &RangeTable{ {0x0cca, 0x0ccd, 1}, {0x0cd5, 0x0cd6, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d00, 0x0d03, 1}, + {0x0cf3, 0x0d00, 13}, + {0x0d01, 0x0d03, 1}, {0x0d3b, 0x0d3c, 1}, {0x0d3e, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, @@ -1664,7 +1747,7 @@ var _M = &RangeTable{ {0x0e47, 0x0e4e, 1}, {0x0eb1, 0x0eb4, 3}, {0x0eb5, 0x0ebc, 1}, - {0x0ec8, 0x0ecd, 1}, + {0x0ec8, 0x0ece, 1}, {0x0f18, 0x0f19, 1}, {0x0f35, 0x0f39, 2}, {0x0f3e, 0x0f3f, 1}, @@ -1683,22 +1766,22 @@ var _M = &RangeTable{ {0x108f, 0x109a, 11}, {0x109b, 0x109d, 1}, {0x135d, 0x135f, 1}, - {0x1712, 0x1714, 1}, + {0x1712, 0x1715, 1}, {0x1732, 0x1734, 1}, {0x1752, 0x1753, 1}, {0x1772, 0x1773, 1}, {0x17b4, 0x17d3, 1}, {0x17dd, 0x180b, 46}, {0x180c, 0x180d, 1}, - {0x1885, 0x1886, 1}, - {0x18a9, 0x1920, 119}, - {0x1921, 0x192b, 1}, + {0x180f, 0x1885, 118}, + {0x1886, 0x18a9, 35}, + {0x1920, 0x192b, 1}, {0x1930, 0x193b, 1}, {0x1a17, 0x1a1b, 1}, {0x1a55, 0x1a5e, 1}, {0x1a60, 0x1a7c, 1}, {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1ac0, 1}, + {0x1ab1, 0x1ace, 1}, {0x1b00, 0x1b04, 1}, {0x1b34, 0x1b44, 1}, {0x1b6b, 0x1b73, 1}, @@ -1710,8 +1793,7 @@ var _M = &RangeTable{ {0x1cd4, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf7, 0x1cf9, 1}, - {0x1dc0, 0x1df9, 1}, - {0x1dfb, 0x1dff, 1}, + {0x1dc0, 0x1dff, 1}, {0x20d0, 0x20f0, 1}, {0x2cef, 0x2cf1, 1}, {0x2d7f, 0x2de0, 97}, @@ -1763,12 +1845,17 @@ var _M = &RangeTable{ {0x10ae6, 0x10d24, 574}, {0x10d25, 0x10d27, 1}, {0x10eab, 0x10eac, 1}, + {0x10efd, 0x10eff, 1}, {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, {0x11000, 0x11002, 1}, {0x11038, 0x11046, 1}, - {0x1107f, 0x11082, 1}, + {0x11070, 0x11073, 3}, + {0x11074, 0x1107f, 11}, + {0x11080, 0x11082, 1}, {0x110b0, 0x110ba, 1}, - {0x11100, 0x11102, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, {0x11127, 0x11134, 1}, {0x11145, 0x11146, 1}, {0x11173, 0x11180, 13}, @@ -1777,8 +1864,8 @@ var _M = &RangeTable{ {0x111c9, 0x111cc, 1}, {0x111ce, 0x111cf, 1}, {0x1122c, 0x11237, 1}, - {0x1123e, 0x112df, 161}, - {0x112e0, 0x112ea, 1}, + {0x1123e, 0x11241, 3}, + {0x112df, 0x112ea, 1}, {0x11300, 0x11303, 1}, {0x1133b, 0x1133c, 1}, {0x1133e, 0x11344, 1}, @@ -1825,6 +1912,12 @@ var _M = &RangeTable{ {0x11d90, 0x11d91, 1}, {0x11d93, 0x11d97, 1}, {0x11ef3, 0x11ef6, 1}, + {0x11f00, 0x11f01, 1}, + {0x11f03, 0x11f34, 49}, + {0x11f35, 0x11f3a, 1}, + {0x11f3e, 0x11f42, 1}, + {0x13440, 0x13447, 7}, + {0x13448, 0x13455, 1}, {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f4f, 0x16f51, 2}, @@ -1832,8 +1925,10 @@ var _M = &RangeTable{ {0x16f8f, 0x16f92, 1}, {0x16fe4, 0x16ff0, 12}, {0x16ff1, 0x1bc9d, 19628}, - {0x1bc9e, 0x1d165, 5319}, - {0x1d166, 0x1d169, 1}, + {0x1bc9e, 0x1cf00, 4706}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d165, 0x1d169, 1}, {0x1d16d, 0x1d172, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, @@ -1849,8 +1944,11 @@ var _M = &RangeTable{ {0x1e01b, 0x1e021, 1}, {0x1e023, 0x1e024, 1}, {0x1e026, 0x1e02a, 1}, - {0x1e130, 0x1e136, 1}, - {0x1e2ec, 0x1e2ef, 1}, + {0x1e08f, 0x1e130, 161}, + {0x1e131, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e4ec, 0x1e4ef, 1}, {0x1e8d0, 0x1e8d6, 1}, {0x1e944, 0x1e94a, 1}, {0xe0100, 0xe01ef, 1}, @@ -1890,8 +1988,9 @@ var _Mc = &RangeTable{ {0x0cc7, 0x0cc8, 1}, {0x0cca, 0x0ccb, 1}, {0x0cd5, 0x0cd6, 1}, - {0x0d02, 0x0d03, 1}, - {0x0d3e, 0x0d40, 1}, + {0x0cf3, 0x0d02, 15}, + {0x0d03, 0x0d3e, 59}, + {0x0d3f, 0x0d40, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4c, 1}, {0x0d57, 0x0d82, 43}, @@ -1911,6 +2010,7 @@ var _Mc = &RangeTable{ {0x1087, 0x108c, 1}, {0x108f, 0x109a, 11}, {0x109b, 0x109c, 1}, + {0x1715, 0x1734, 31}, {0x17b6, 0x17be, 8}, {0x17bf, 0x17c5, 1}, {0x17c7, 0x17c8, 1}, @@ -2009,7 +2109,10 @@ var _Mc = &RangeTable{ {0x11d8a, 0x11d8e, 1}, {0x11d93, 0x11d94, 1}, {0x11d96, 0x11ef5, 351}, - {0x11ef6, 0x16f51, 20571}, + {0x11ef6, 0x11f03, 13}, + {0x11f34, 0x11f35, 1}, + {0x11f3e, 0x11f3f, 1}, + {0x11f41, 0x16f51, 20496}, {0x16f52, 0x16f87, 1}, {0x16ff0, 0x16ff1, 1}, {0x1d165, 0x1d166, 1}, @@ -2052,7 +2155,8 @@ var _Mn = &RangeTable{ {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, {0x0859, 0x085b, 1}, - {0x08d3, 0x08e1, 1}, + {0x0898, 0x089f, 1}, + {0x08ca, 0x08e1, 1}, {0x08e3, 0x0902, 1}, {0x093a, 0x093c, 2}, {0x0941, 0x0948, 1}, @@ -2085,7 +2189,8 @@ var _Mn = &RangeTable{ {0x0b63, 0x0b82, 31}, {0x0bc0, 0x0bcd, 13}, {0x0c00, 0x0c04, 4}, - {0x0c3e, 0x0c40, 1}, + {0x0c3c, 0x0c3e, 2}, + {0x0c3f, 0x0c40, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, @@ -2106,7 +2211,7 @@ var _Mn = &RangeTable{ {0x0e47, 0x0e4e, 1}, {0x0eb1, 0x0eb4, 3}, {0x0eb5, 0x0ebc, 1}, - {0x0ec8, 0x0ecd, 1}, + {0x0ec8, 0x0ece, 1}, {0x0f18, 0x0f19, 1}, {0x0f35, 0x0f39, 2}, {0x0f71, 0x0f7e, 1}, @@ -2127,7 +2232,7 @@ var _Mn = &RangeTable{ {0x109d, 0x135d, 704}, {0x135e, 0x135f, 1}, {0x1712, 0x1714, 1}, - {0x1732, 0x1734, 1}, + {0x1732, 0x1733, 1}, {0x1752, 0x1753, 1}, {0x1772, 0x1773, 1}, {0x17b4, 0x17b5, 1}, @@ -2136,9 +2241,9 @@ var _Mn = &RangeTable{ {0x17ca, 0x17d3, 1}, {0x17dd, 0x180b, 46}, {0x180c, 0x180d, 1}, - {0x1885, 0x1886, 1}, - {0x18a9, 0x1920, 119}, - {0x1921, 0x1922, 1}, + {0x180f, 0x1885, 118}, + {0x1886, 0x18a9, 35}, + {0x1920, 0x1922, 1}, {0x1927, 0x1928, 1}, {0x1932, 0x1939, 7}, {0x193a, 0x193b, 1}, @@ -2150,7 +2255,7 @@ var _Mn = &RangeTable{ {0x1a73, 0x1a7c, 1}, {0x1a7f, 0x1ab0, 49}, {0x1ab1, 0x1abd, 1}, - {0x1abf, 0x1ac0, 1}, + {0x1abf, 0x1ace, 1}, {0x1b00, 0x1b03, 1}, {0x1b34, 0x1b36, 2}, {0x1b37, 0x1b3a, 1}, @@ -2170,8 +2275,7 @@ var _Mn = &RangeTable{ {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df9, 1}, - {0x1dfb, 0x1dff, 1}, + {0x1dc0, 0x1dff, 1}, {0x20d0, 0x20dc, 1}, {0x20e1, 0x20e5, 4}, {0x20e6, 0x20f0, 1}, @@ -2223,13 +2327,18 @@ var _Mn = &RangeTable{ {0x10ae6, 0x10d24, 574}, {0x10d25, 0x10d27, 1}, {0x10eab, 0x10eac, 1}, + {0x10efd, 0x10eff, 1}, {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, {0x11001, 0x11038, 55}, {0x11039, 0x11046, 1}, - {0x1107f, 0x11081, 1}, + {0x11070, 0x11073, 3}, + {0x11074, 0x1107f, 11}, + {0x11080, 0x11081, 1}, {0x110b3, 0x110b6, 1}, {0x110b9, 0x110ba, 1}, - {0x11100, 0x11102, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, {0x11127, 0x1112b, 1}, {0x1112d, 0x11134, 1}, {0x11173, 0x11180, 13}, @@ -2240,8 +2349,8 @@ var _Mn = &RangeTable{ {0x11230, 0x11231, 1}, {0x11234, 0x11236, 2}, {0x11237, 0x1123e, 7}, - {0x112df, 0x112e3, 4}, - {0x112e4, 0x112ea, 1}, + {0x11241, 0x112df, 158}, + {0x112e3, 0x112ea, 1}, {0x11300, 0x11301, 1}, {0x1133b, 0x1133c, 1}, {0x11340, 0x11366, 38}, @@ -2296,14 +2405,21 @@ var _Mn = &RangeTable{ {0x11d47, 0x11d90, 73}, {0x11d91, 0x11d95, 4}, {0x11d97, 0x11ef3, 348}, - {0x11ef4, 0x16af0, 19452}, - {0x16af1, 0x16af4, 1}, + {0x11ef4, 0x11f00, 12}, + {0x11f01, 0x11f36, 53}, + {0x11f37, 0x11f3a, 1}, + {0x11f40, 0x11f42, 2}, + {0x13440, 0x13447, 7}, + {0x13448, 0x13455, 1}, + {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f4f, 0x16f8f, 64}, {0x16f90, 0x16f92, 1}, {0x16fe4, 0x1bc9d, 19641}, - {0x1bc9e, 0x1d167, 5321}, - {0x1d168, 0x1d169, 1}, + {0x1bc9e, 0x1cf00, 4706}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, @@ -2318,8 +2434,11 @@ var _Mn = &RangeTable{ {0x1e01b, 0x1e021, 1}, {0x1e023, 0x1e024, 1}, {0x1e026, 0x1e02a, 1}, - {0x1e130, 0x1e136, 1}, - {0x1e2ec, 0x1e2ef, 1}, + {0x1e08f, 0x1e130, 161}, + {0x1e131, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e4ec, 0x1e4ef, 1}, {0x1e8d0, 0x1e8d6, 1}, {0x1e944, 0x1e94a, 1}, {0xe0100, 0xe01ef, 1}, @@ -2441,17 +2560,21 @@ var _N = &RangeTable{ {0x11c50, 0x11c6c, 1}, {0x11d50, 0x11d59, 1}, {0x11da0, 0x11da9, 1}, + {0x11f50, 0x11f59, 1}, {0x11fc0, 0x11fd4, 1}, {0x12400, 0x1246e, 1}, {0x16a60, 0x16a69, 1}, + {0x16ac0, 0x16ac9, 1}, {0x16b50, 0x16b59, 1}, {0x16b5b, 0x16b61, 1}, {0x16e80, 0x16e96, 1}, + {0x1d2c0, 0x1d2d3, 1}, {0x1d2e0, 0x1d2f3, 1}, {0x1d360, 0x1d378, 1}, {0x1d7ce, 0x1d7ff, 1}, {0x1e140, 0x1e149, 1}, {0x1e2f0, 0x1e2f9, 1}, + {0x1e4f0, 0x1e4f9, 1}, {0x1e8c7, 0x1e8cf, 1}, {0x1e950, 0x1e959, 1}, {0x1ec71, 0x1ecab, 1}, @@ -2523,11 +2646,14 @@ var _Nd = &RangeTable{ {0x11c50, 0x11c59, 1}, {0x11d50, 0x11d59, 1}, {0x11da0, 0x11da9, 1}, + {0x11f50, 0x11f59, 1}, {0x16a60, 0x16a69, 1}, + {0x16ac0, 0x16ac9, 1}, {0x16b50, 0x16b59, 1}, {0x1d7ce, 0x1d7ff, 1}, {0x1e140, 0x1e149, 1}, {0x1e2f0, 0x1e2f9, 1}, + {0x1e4f0, 0x1e4f9, 1}, {0x1e950, 0x1e959, 1}, {0x1fbf0, 0x1fbf9, 1}, }, @@ -2617,6 +2743,7 @@ var _No = &RangeTable{ {0x11fc0, 0x11fd4, 1}, {0x16b5b, 0x16b61, 1}, {0x16e80, 0x16e96, 1}, + {0x1d2c0, 0x1d2d3, 1}, {0x1d2e0, 0x1d2f3, 1}, {0x1d360, 0x1d378, 1}, {0x1e8c7, 0x1e8cf, 1}, @@ -2651,9 +2778,9 @@ var _P = &RangeTable{ {0x05f3, 0x05f4, 1}, {0x0609, 0x060a, 1}, {0x060c, 0x060d, 1}, - {0x061b, 0x061e, 3}, - {0x061f, 0x066a, 75}, - {0x066b, 0x066d, 1}, + {0x061b, 0x061d, 2}, + {0x061e, 0x061f, 1}, + {0x066a, 0x066d, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x070d, 1}, {0x07f7, 0x07f9, 1}, @@ -2686,6 +2813,7 @@ var _P = &RangeTable{ {0x1aa0, 0x1aa6, 1}, {0x1aa8, 0x1aad, 1}, {0x1b5a, 0x1b60, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1bfc, 0x1bff, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, @@ -2710,8 +2838,8 @@ var _P = &RangeTable{ {0x2d70, 0x2e00, 144}, {0x2e01, 0x2e2e, 1}, {0x2e30, 0x2e4f, 1}, - {0x2e52, 0x3001, 431}, - {0x3002, 0x3003, 1}, + {0x2e52, 0x2e5d, 1}, + {0x3001, 0x3003, 1}, {0x3008, 0x3011, 1}, {0x3014, 0x301f, 1}, {0x3030, 0x303d, 13}, @@ -2759,6 +2887,7 @@ var _P = &RangeTable{ {0x10b99, 0x10b9c, 1}, {0x10ead, 0x10f55, 168}, {0x10f56, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x1104d, 1}, {0x110bb, 0x110bc, 1}, {0x110be, 0x110c1, 1}, @@ -2775,18 +2904,22 @@ var _P = &RangeTable{ {0x115c1, 0x115d7, 1}, {0x11641, 0x11643, 1}, {0x11660, 0x1166c, 1}, - {0x1173c, 0x1173e, 1}, + {0x116b9, 0x1173c, 131}, + {0x1173d, 0x1173e, 1}, {0x1183b, 0x11944, 265}, {0x11945, 0x11946, 1}, {0x119e2, 0x11a3f, 93}, {0x11a40, 0x11a46, 1}, {0x11a9a, 0x11a9c, 1}, {0x11a9e, 0x11aa2, 1}, + {0x11b00, 0x11b09, 1}, {0x11c41, 0x11c45, 1}, {0x11c70, 0x11c71, 1}, {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f4f, 1}, {0x11fff, 0x12470, 1137}, {0x12471, 0x12474, 1}, + {0x12ff1, 0x12ff2, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b3b, 1}, @@ -2817,11 +2950,11 @@ var _Pd = &RangeTable{ {0x2011, 0x2015, 1}, {0x2e17, 0x2e1a, 3}, {0x2e3a, 0x2e3b, 1}, - {0x2e40, 0x301c, 476}, - {0x3030, 0x30a0, 112}, - {0xfe31, 0xfe32, 1}, - {0xfe58, 0xfe63, 11}, - {0xff0d, 0xff0d, 1}, + {0x2e40, 0x2e5d, 29}, + {0x301c, 0x3030, 20}, + {0x30a0, 0xfe31, 52625}, + {0xfe32, 0xfe58, 38}, + {0xfe63, 0xff0d, 170}, }, R32: []Range32{ {0x10ead, 0x10ead, 1}, @@ -2843,6 +2976,7 @@ var _Pe = &RangeTable{ {0x29d9, 0x29db, 2}, {0x29fd, 0x2e23, 1062}, {0x2e25, 0x2e29, 2}, + {0x2e56, 0x2e5c, 2}, {0x3009, 0x3011, 2}, {0x3015, 0x301b, 2}, {0x301e, 0x301f, 1}, @@ -2895,9 +3029,9 @@ var _Po = &RangeTable{ {0x05f3, 0x05f4, 1}, {0x0609, 0x060a, 1}, {0x060c, 0x060d, 1}, - {0x061b, 0x061e, 3}, - {0x061f, 0x066a, 75}, - {0x066b, 0x066d, 1}, + {0x061b, 0x061d, 2}, + {0x061e, 0x061f, 1}, + {0x066a, 0x066d, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x070d, 1}, {0x07f7, 0x07f9, 1}, @@ -2928,6 +3062,7 @@ var _Po = &RangeTable{ {0x1aa0, 0x1aa6, 1}, {0x1aa8, 0x1aad, 1}, {0x1b5a, 0x1b60, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1bfc, 0x1bff, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, @@ -2956,8 +3091,8 @@ var _Po = &RangeTable{ {0x2e3c, 0x2e3f, 1}, {0x2e41, 0x2e43, 2}, {0x2e44, 0x2e4f, 1}, - {0x2e52, 0x3001, 431}, - {0x3002, 0x3003, 1}, + {0x2e52, 0x2e54, 1}, + {0x3001, 0x3003, 1}, {0x303d, 0x30fb, 190}, {0xa4fe, 0xa4ff, 1}, {0xa60d, 0xa60f, 1}, @@ -3003,6 +3138,7 @@ var _Po = &RangeTable{ {0x10b39, 0x10b3f, 1}, {0x10b99, 0x10b9c, 1}, {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x1104d, 1}, {0x110bb, 0x110bc, 1}, {0x110be, 0x110c1, 1}, @@ -3019,18 +3155,22 @@ var _Po = &RangeTable{ {0x115c1, 0x115d7, 1}, {0x11641, 0x11643, 1}, {0x11660, 0x1166c, 1}, - {0x1173c, 0x1173e, 1}, + {0x116b9, 0x1173c, 131}, + {0x1173d, 0x1173e, 1}, {0x1183b, 0x11944, 265}, {0x11945, 0x11946, 1}, {0x119e2, 0x11a3f, 93}, {0x11a40, 0x11a46, 1}, {0x11a9a, 0x11a9c, 1}, {0x11a9e, 0x11aa2, 1}, + {0x11b00, 0x11b09, 1}, {0x11c41, 0x11c45, 1}, {0x11c70, 0x11c71, 1}, {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f4f, 1}, {0x11fff, 0x12470, 1137}, {0x12471, 0x12474, 1}, + {0x12ff1, 0x12ff2, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b3b, 1}, @@ -3059,8 +3199,9 @@ var _Ps = &RangeTable{ {0x29d8, 0x29da, 2}, {0x29fc, 0x2e22, 1062}, {0x2e24, 0x2e28, 2}, - {0x2e42, 0x3008, 454}, - {0x300a, 0x3010, 2}, + {0x2e42, 0x2e55, 19}, + {0x2e57, 0x2e5b, 2}, + {0x3008, 0x3010, 2}, {0x3014, 0x301a, 2}, {0x301d, 0xfd3f, 52514}, {0xfe17, 0xfe35, 30}, @@ -3101,10 +3242,11 @@ var _S = &RangeTable{ {0x06e9, 0x06fd, 20}, {0x06fe, 0x07f6, 248}, {0x07fe, 0x07ff, 1}, - {0x09f2, 0x09f3, 1}, - {0x09fa, 0x09fb, 1}, - {0x0af1, 0x0b70, 127}, - {0x0bf3, 0x0bfa, 1}, + {0x0888, 0x09f2, 362}, + {0x09f3, 0x09fa, 7}, + {0x09fb, 0x0af1, 246}, + {0x0b70, 0x0bf3, 131}, + {0x0bf4, 0x0bfa, 1}, {0x0c7f, 0x0d4f, 208}, {0x0d79, 0x0e3f, 198}, {0x0f01, 0x0f03, 1}, @@ -3132,7 +3274,7 @@ var _S = &RangeTable{ {0x2044, 0x2052, 14}, {0x207a, 0x207c, 1}, {0x208a, 0x208c, 1}, - {0x20a0, 0x20bf, 1}, + {0x20a0, 0x20c0, 1}, {0x2100, 0x2101, 1}, {0x2103, 0x2106, 1}, {0x2108, 0x2109, 1}, @@ -3190,8 +3332,10 @@ var _S = &RangeTable{ {0xaa77, 0xaa79, 1}, {0xab5b, 0xab6a, 15}, {0xab6b, 0xfb29, 20414}, - {0xfbb2, 0xfbc1, 1}, - {0xfdfc, 0xfdfd, 1}, + {0xfbb2, 0xfbc2, 1}, + {0xfd40, 0xfd4f, 1}, + {0xfdcf, 0xfdfc, 45}, + {0xfdfd, 0xfdff, 1}, {0xfe62, 0xfe64, 2}, {0xfe65, 0xfe66, 1}, {0xfe69, 0xff04, 155}, @@ -3215,13 +3359,14 @@ var _S = &RangeTable{ {0x11fd5, 0x11ff1, 1}, {0x16b3c, 0x16b3f, 1}, {0x16b45, 0x1bc9c, 20823}, + {0x1cf50, 0x1cfc3, 1}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, {0x1d129, 0x1d164, 1}, {0x1d16a, 0x1d16c, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1e8, 1}, + {0x1d1ae, 0x1d1ea, 1}, {0x1d200, 0x1d241, 1}, {0x1d245, 0x1d300, 187}, {0x1d301, 0x1d356, 1}, @@ -3252,28 +3397,27 @@ var _S = &RangeTable{ {0x1f250, 0x1f251, 1}, {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f6d7, 1}, - {0x1f6e0, 0x1f6ec, 1}, + {0x1f6dc, 0x1f6ec, 1}, {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f773, 1}, - {0x1f780, 0x1f7d8, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, {0x1f7e0, 0x1f7eb, 1}, - {0x1f800, 0x1f80b, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, {0x1f810, 0x1f847, 1}, {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1f978, 1}, - {0x1f97a, 0x1f9cb, 1}, - {0x1f9cd, 0x1fa53, 1}, + {0x1f900, 0x1fa53, 1}, {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa74, 1}, - {0x1fa78, 0x1fa7a, 1}, - {0x1fa80, 0x1fa86, 1}, - {0x1fa90, 0x1faa8, 1}, - {0x1fab0, 0x1fab6, 1}, - {0x1fac0, 0x1fac2, 1}, - {0x1fad0, 0x1fad6, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, {0x1fb00, 0x1fb92, 1}, {0x1fb94, 0x1fbca, 1}, }, @@ -3290,7 +3434,7 @@ var _Sc = &RangeTable{ {0x09fb, 0x0af1, 246}, {0x0bf9, 0x0e3f, 582}, {0x17db, 0x20a0, 2245}, - {0x20a1, 0x20bf, 1}, + {0x20a1, 0x20c0, 1}, {0xa838, 0xfdfc, 21956}, {0xfe69, 0xff04, 155}, {0xffe0, 0xffe1, 1}, @@ -3314,8 +3458,9 @@ var _Sk = &RangeTable{ {0x02ed, 0x02ef, 2}, {0x02f0, 0x02ff, 1}, {0x0375, 0x0384, 15}, - {0x0385, 0x1fbd, 7224}, - {0x1fbf, 0x1fc1, 1}, + {0x0385, 0x0888, 1283}, + {0x1fbd, 0x1fbf, 2}, + {0x1fc0, 0x1fc1, 1}, {0x1fcd, 0x1fcf, 1}, {0x1fdd, 0x1fdf, 1}, {0x1fed, 0x1fef, 1}, @@ -3326,7 +3471,7 @@ var _Sk = &RangeTable{ {0xa789, 0xa78a, 1}, {0xab5b, 0xab6a, 15}, {0xab6b, 0xfbb2, 20551}, - {0xfbb3, 0xfbc1, 1}, + {0xfbb3, 0xfbc2, 1}, {0xff3e, 0xff40, 2}, {0xffe3, 0xffe3, 1}, }, @@ -3488,10 +3633,12 @@ var _So = &RangeTable{ {0xa836, 0xa837, 1}, {0xa839, 0xaa77, 574}, {0xaa78, 0xaa79, 1}, - {0xfdfd, 0xffe4, 487}, - {0xffe8, 0xffed, 5}, - {0xffee, 0xfffc, 14}, - {0xfffd, 0xfffd, 1}, + {0xfd40, 0xfd4f, 1}, + {0xfdcf, 0xfdfd, 46}, + {0xfdfe, 0xfdff, 1}, + {0xffe4, 0xffe8, 4}, + {0xffed, 0xffee, 1}, + {0xfffc, 0xfffd, 1}, }, R32: []Range32{ {0x10137, 0x1013f, 1}, @@ -3506,13 +3653,14 @@ var _So = &RangeTable{ {0x11fe1, 0x11ff1, 1}, {0x16b3c, 0x16b3f, 1}, {0x16b45, 0x1bc9c, 20823}, + {0x1cf50, 0x1cfc3, 1}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, {0x1d129, 0x1d164, 1}, {0x1d16a, 0x1d16c, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1e8, 1}, + {0x1d1ae, 0x1d1ea, 1}, {0x1d200, 0x1d241, 1}, {0x1d245, 0x1d300, 187}, {0x1d301, 0x1d356, 1}, @@ -3537,28 +3685,27 @@ var _So = &RangeTable{ {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f3fa, 1}, {0x1f400, 0x1f6d7, 1}, - {0x1f6e0, 0x1f6ec, 1}, + {0x1f6dc, 0x1f6ec, 1}, {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f773, 1}, - {0x1f780, 0x1f7d8, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, {0x1f7e0, 0x1f7eb, 1}, - {0x1f800, 0x1f80b, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, {0x1f810, 0x1f847, 1}, {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1f978, 1}, - {0x1f97a, 0x1f9cb, 1}, - {0x1f9cd, 0x1fa53, 1}, + {0x1f900, 0x1fa53, 1}, {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa74, 1}, - {0x1fa78, 0x1fa7a, 1}, - {0x1fa80, 0x1fa86, 1}, - {0x1fa90, 0x1faa8, 1}, - {0x1fab0, 0x1fab6, 1}, - {0x1fac0, 0x1fac2, 1}, - {0x1fad0, 0x1fad6, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, {0x1fb00, 0x1fb92, 1}, {0x1fb94, 0x1fbca, 1}, }, @@ -3681,6 +3828,7 @@ var Scripts = map[string]*RangeTable{ "Coptic": Coptic, "Cuneiform": Cuneiform, "Cypriot": Cypriot, + "Cypro_Minoan": Cypro_Minoan, "Cyrillic": Cyrillic, "Deseret": Deseret, "Devanagari": Devanagari, @@ -3714,6 +3862,7 @@ var Scripts = map[string]*RangeTable{ "Kaithi": Kaithi, "Kannada": Kannada, "Katakana": Katakana, + "Kawi": Kawi, "Kayah_Li": Kayah_Li, "Kharoshthi": Kharoshthi, "Khitan_Small_Script": Khitan_Small_Script, @@ -3748,6 +3897,7 @@ var Scripts = map[string]*RangeTable{ "Multani": Multani, "Myanmar": Myanmar, "Nabataean": Nabataean, + "Nag_Mundari": Nag_Mundari, "Nandinagari": Nandinagari, "New_Tai_Lue": New_Tai_Lue, "Newa": Newa, @@ -3764,6 +3914,7 @@ var Scripts = map[string]*RangeTable{ "Old_Sogdian": Old_Sogdian, "Old_South_Arabian": Old_South_Arabian, "Old_Turkic": Old_Turkic, + "Old_Uyghur": Old_Uyghur, "Oriya": Oriya, "Osage": Osage, "Osmanya": Osmanya, @@ -3795,6 +3946,7 @@ var Scripts = map[string]*RangeTable{ "Tai_Viet": Tai_Viet, "Takri": Takri, "Tamil": Tamil, + "Tangsa": Tangsa, "Tangut": Tangut, "Telugu": Telugu, "Thaana": Thaana, @@ -3802,8 +3954,10 @@ var Scripts = map[string]*RangeTable{ "Tibetan": Tibetan, "Tifinagh": Tifinagh, "Tirhuta": Tirhuta, + "Toto": Toto, "Ugaritic": Ugaritic, "Vai": Vai, + "Vithkuqi": Vithkuqi, "Wancho": Wancho, "Warang_Citi": Warang_Citi, "Yezidi": Yezidi, @@ -3825,7 +3979,7 @@ var _Ahom = &RangeTable{ R32: []Range32{ {0x11700, 0x1171a, 1}, {0x1171d, 0x1172b, 1}, - {0x11730, 0x1173f, 1}, + {0x11730, 0x11746, 1}, }, } @@ -3841,27 +3995,29 @@ var _Arabic = &RangeTable{ {0x0600, 0x0604, 1}, {0x0606, 0x060b, 1}, {0x060d, 0x061a, 1}, - {0x061c, 0x0620, 2}, - {0x0621, 0x063f, 1}, + {0x061c, 0x061e, 1}, + {0x0620, 0x063f, 1}, {0x0641, 0x064a, 1}, {0x0656, 0x066f, 1}, {0x0671, 0x06dc, 1}, {0x06de, 0x06ff, 1}, {0x0750, 0x077f, 1}, - {0x08a0, 0x08b4, 1}, - {0x08b6, 0x08c7, 1}, - {0x08d3, 0x08e1, 1}, + {0x0870, 0x088e, 1}, + {0x0890, 0x0891, 1}, + {0x0898, 0x08e1, 1}, {0x08e3, 0x08ff, 1}, - {0xfb50, 0xfbc1, 1}, + {0xfb50, 0xfbc2, 1}, {0xfbd3, 0xfd3d, 1}, - {0xfd50, 0xfd8f, 1}, + {0xfd40, 0xfd8f, 1}, {0xfd92, 0xfdc7, 1}, - {0xfdf0, 0xfdfd, 1}, + {0xfdcf, 0xfdf0, 33}, + {0xfdf1, 0xfdff, 1}, {0xfe70, 0xfe74, 1}, {0xfe76, 0xfefc, 1}, }, R32: []Range32{ {0x10e60, 0x10e7e, 1}, + {0x10efd, 0x10eff, 1}, {0x1ee00, 0x1ee03, 1}, {0x1ee05, 0x1ee1f, 1}, {0x1ee21, 0x1ee22, 1}, @@ -3909,8 +4065,8 @@ var _Avestan = &RangeTable{ var _Balinese = &RangeTable{ R16: []Range16{ - {0x1b00, 0x1b4b, 1}, - {0x1b50, 0x1b7c, 1}, + {0x1b00, 0x1b4c, 1}, + {0x1b50, 0x1b7e, 1}, }, } @@ -3979,7 +4135,7 @@ var _Brahmi = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x11000, 0x1104d, 1}, - {0x11052, 0x1106f, 1}, + {0x11052, 0x11075, 1}, {0x1107f, 0x1107f, 1}, }, } @@ -4008,6 +4164,9 @@ var _Canadian_Aboriginal = &RangeTable{ {0x1400, 0x167f, 1}, {0x18b0, 0x18f5, 1}, }, + R32: []Range32{ + {0x11ab0, 0x11abf, 1}, + }, } var _Carian = &RangeTable{ @@ -4091,7 +4250,7 @@ var _Common = &RangeTable{ {0x2066, 0x2070, 1}, {0x2074, 0x207e, 1}, {0x2080, 0x208e, 1}, - {0x20a0, 0x20bf, 1}, + {0x20a0, 0x20c0, 1}, {0x2100, 0x2125, 1}, {0x2127, 0x2129, 1}, {0x212c, 0x2131, 1}, @@ -4104,7 +4263,7 @@ var _Common = &RangeTable{ {0x2900, 0x2b73, 1}, {0x2b76, 0x2b95, 1}, {0x2b97, 0x2bff, 1}, - {0x2e00, 0x2e52, 1}, + {0x2e00, 0x2e5d, 1}, {0x2ff0, 0x2ffb, 1}, {0x3000, 0x3004, 1}, {0x3006, 0x3008, 2}, @@ -4149,15 +4308,16 @@ var _Common = &RangeTable{ {0x10190, 0x1019c, 1}, {0x101d0, 0x101fc, 1}, {0x102e1, 0x102fb, 1}, - {0x16fe2, 0x16fe3, 1}, {0x1bca0, 0x1bca3, 1}, + {0x1cf50, 0x1cfc3, 1}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, {0x1d129, 0x1d166, 1}, {0x1d16a, 0x1d17a, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1e8, 1}, + {0x1d1ae, 0x1d1ea, 1}, + {0x1d2c0, 0x1d2d3, 1}, {0x1d2e0, 0x1d2f3, 1}, {0x1d300, 0x1d356, 1}, {0x1d360, 0x1d378, 1}, @@ -4198,28 +4358,27 @@ var _Common = &RangeTable{ {0x1f250, 0x1f251, 1}, {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f6d7, 1}, - {0x1f6e0, 0x1f6ec, 1}, + {0x1f6dc, 0x1f6ec, 1}, {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f773, 1}, - {0x1f780, 0x1f7d8, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, {0x1f7e0, 0x1f7eb, 1}, - {0x1f800, 0x1f80b, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, {0x1f810, 0x1f847, 1}, {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1f978, 1}, - {0x1f97a, 0x1f9cb, 1}, - {0x1f9cd, 0x1fa53, 1}, + {0x1f900, 0x1fa53, 1}, {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa74, 1}, - {0x1fa78, 0x1fa7a, 1}, - {0x1fa80, 0x1fa86, 1}, - {0x1fa90, 0x1faa8, 1}, - {0x1fab0, 0x1fab6, 1}, - {0x1fac0, 0x1fac2, 1}, - {0x1fad0, 0x1fad6, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, {0x1fb00, 0x1fb92, 1}, {0x1fb94, 0x1fbca, 1}, {0x1fbf0, 0x1fbf9, 1}, @@ -4258,6 +4417,13 @@ var _Cypriot = &RangeTable{ }, } +var _Cypro_Minoan = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x12f90, 0x12ff2, 1}, + }, +} + var _Cyrillic = &RangeTable{ R16: []Range16{ {0x0400, 0x0484, 1}, @@ -4268,6 +4434,10 @@ var _Cyrillic = &RangeTable{ {0xa640, 0xa69f, 1}, {0xfe2e, 0xfe2f, 1}, }, + R32: []Range32{ + {0x1e030, 0x1e06d, 1}, + {0x1e08f, 0x1e08f, 1}, + }, } var _Deseret = &RangeTable{ @@ -4284,6 +4454,9 @@ var _Devanagari = &RangeTable{ {0x0966, 0x097f, 1}, {0xa8e0, 0xa8ff, 1}, }, + R32: []Range32{ + {0x11b00, 0x11b09, 1}, + }, } var _Dives_Akuru = &RangeTable{ @@ -4321,8 +4494,7 @@ var _Duployan = &RangeTable{ var _Egyptian_Hieroglyphs = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x13000, 0x1342e, 1}, - {0x13430, 0x13438, 1}, + {0x13000, 0x13455, 1}, }, } @@ -4375,6 +4547,12 @@ var _Ethiopic = &RangeTable{ {0xab20, 0xab26, 1}, {0xab28, 0xab2e, 1}, }, + R32: []Range32{ + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, + }, } var _Georgian = &RangeTable{ @@ -4392,8 +4570,7 @@ var _Georgian = &RangeTable{ var _Glagolitic = &RangeTable{ R16: []Range16{ - {0x2c00, 0x2c2e, 1}, - {0x2c30, 0x2c5e, 1}, + {0x2c00, 0x2c5f, 1}, }, R32: []Range32{ {0x1e000, 0x1e006, 1}, @@ -4531,19 +4708,21 @@ var _Han = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303b, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, + {0x4e00, 0x9fff, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, R32: []Range32{ + {0x16fe2, 0x16fe3, 1}, {0x16ff0, 0x16ff1, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, } @@ -4609,8 +4788,9 @@ var _Hiragana = &RangeTable{ {0x309d, 0x309f, 1}, }, R32: []Range32{ - {0x1b001, 0x1b11e, 1}, - {0x1b150, 0x1b152, 1}, + {0x1b001, 0x1b11f, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, {0x1f200, 0x1f200, 1}, }, } @@ -4630,14 +4810,13 @@ var _Inherited = &RangeTable{ {0x064b, 0x0655, 1}, {0x0670, 0x0951, 737}, {0x0952, 0x0954, 1}, - {0x1ab0, 0x1ac0, 1}, + {0x1ab0, 0x1ace, 1}, {0x1cd0, 0x1cd2, 1}, {0x1cd4, 0x1ce0, 1}, {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df9, 1}, - {0x1dfb, 0x1dff, 1}, + {0x1dc0, 0x1dff, 1}, {0x200c, 0x200d, 1}, {0x20d0, 0x20f0, 1}, {0x302a, 0x302d, 1}, @@ -4647,8 +4826,10 @@ var _Inherited = &RangeTable{ }, R32: []Range32{ {0x101fd, 0x102e0, 227}, - {0x1133b, 0x1d167, 48684}, - {0x1d168, 0x1d169, 1}, + {0x1133b, 0x1cf00, 48069}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, @@ -4683,7 +4864,7 @@ var _Javanese = &RangeTable{ var _Kaithi = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x11080, 0x110c1, 1}, + {0x11080, 0x110c2, 1}, {0x110cd, 0x110cd, 1}, }, } @@ -4699,10 +4880,10 @@ var _Kannada = &RangeTable{ {0x0cc6, 0x0cc8, 1}, {0x0cca, 0x0ccd, 1}, {0x0cd5, 0x0cd6, 1}, - {0x0cde, 0x0ce0, 2}, - {0x0ce1, 0x0ce3, 1}, + {0x0cdd, 0x0cde, 1}, + {0x0ce0, 0x0ce3, 1}, {0x0ce6, 0x0cef, 1}, - {0x0cf1, 0x0cf2, 1}, + {0x0cf1, 0x0cf3, 1}, }, } @@ -4717,11 +4898,25 @@ var _Katakana = &RangeTable{ {0xff71, 0xff9d, 1}, }, R32: []Range32{ - {0x1b000, 0x1b164, 356}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1b000, 0x1b120, 288}, + {0x1b121, 0x1b122, 1}, + {0x1b155, 0x1b164, 15}, {0x1b165, 0x1b167, 1}, }, } +var _Kawi = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11f00, 0x11f10, 1}, + {0x11f12, 0x11f3a, 1}, + {0x11f3e, 0x11f59, 1}, + }, +} + var _Kayah_Li = &RangeTable{ R16: []Range16{ {0xa900, 0xa92d, 1}, @@ -4764,7 +4959,7 @@ var _Khojki = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x11200, 0x11211, 1}, - {0x11213, 0x1123e, 1}, + {0x11213, 0x11241, 1}, }, } @@ -4786,7 +4981,7 @@ var _Lao = &RangeTable{ {0x0ea8, 0x0ebd, 1}, {0x0ec0, 0x0ec4, 1}, {0x0ec6, 0x0ec8, 2}, - {0x0ec9, 0x0ecd, 1}, + {0x0ec9, 0x0ece, 1}, {0x0ed0, 0x0ed9, 1}, {0x0edc, 0x0edf, 1}, }, @@ -4814,9 +5009,11 @@ var _Latin = &RangeTable{ {0x2160, 0x2188, 1}, {0x2c60, 0x2c7f, 1}, {0xa722, 0xa787, 1}, - {0xa78b, 0xa7bf, 1}, - {0xa7c2, 0xa7ca, 1}, - {0xa7f5, 0xa7ff, 1}, + {0xa78b, 0xa7ca, 1}, + {0xa7d0, 0xa7d1, 1}, + {0xa7d3, 0xa7d5, 2}, + {0xa7d6, 0xa7d9, 1}, + {0xa7f2, 0xa7ff, 1}, {0xab30, 0xab5a, 1}, {0xab5c, 0xab64, 1}, {0xab66, 0xab69, 1}, @@ -4824,6 +5021,13 @@ var _Latin = &RangeTable{ {0xff21, 0xff3a, 1}, {0xff41, 0xff5a, 1}, }, + R32: []Range32{ + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x1df00, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + }, LatinOffset: 5, } @@ -5014,8 +5218,7 @@ var _Mongolian = &RangeTable{ R16: []Range16{ {0x1800, 0x1801, 1}, {0x1804, 0x1806, 2}, - {0x1807, 0x180e, 1}, - {0x1810, 0x1819, 1}, + {0x1807, 0x1819, 1}, {0x1820, 0x1878, 1}, {0x1880, 0x18aa, 1}, }, @@ -5060,6 +5263,13 @@ var _Nabataean = &RangeTable{ }, } +var _Nag_Mundari = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x1e4d0, 0x1e4f9, 1}, + }, +} + var _Nandinagari = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5183,6 +5393,13 @@ var _Old_Turkic = &RangeTable{ }, } +var _Old_Uyghur = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x10f70, 0x10f89, 1}, + }, +} + var _Oriya = &RangeTable{ R16: []Range16{ {0x0b01, 0x0b03, 1}, @@ -5391,8 +5608,8 @@ var _Syriac = &RangeTable{ var _Tagalog = &RangeTable{ R16: []Range16{ - {0x1700, 0x170c, 1}, - {0x170e, 0x1714, 1}, + {0x1700, 0x1715, 1}, + {0x171f, 0x171f, 1}, }, } @@ -5431,7 +5648,7 @@ var _Tai_Viet = &RangeTable{ var _Takri = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x11680, 0x116b8, 1}, + {0x11680, 0x116b9, 1}, {0x116c0, 0x116c9, 1}, }, } @@ -5460,6 +5677,14 @@ var _Tamil = &RangeTable{ }, } +var _Tangsa = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x16a70, 0x16abe, 1}, + {0x16ac0, 0x16ac9, 1}, + }, +} + var _Tangut = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5476,12 +5701,13 @@ var _Telugu = &RangeTable{ {0x0c0e, 0x0c10, 1}, {0x0c12, 0x0c28, 1}, {0x0c2a, 0x0c39, 1}, - {0x0c3d, 0x0c44, 1}, + {0x0c3c, 0x0c44, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, {0x0c58, 0x0c5a, 1}, - {0x0c60, 0x0c63, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c63, 1}, {0x0c66, 0x0c6f, 1}, {0x0c77, 0x0c7f, 1}, }, @@ -5528,6 +5754,13 @@ var _Tirhuta = &RangeTable{ }, } +var _Toto = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x1e290, 0x1e2ae, 1}, + }, +} + var _Ugaritic = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5542,6 +5775,20 @@ var _Vai = &RangeTable{ }, } +var _Vithkuqi = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, + }, +} + var _Wancho = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5611,6 +5858,7 @@ var ( Coptic = _Coptic // Coptic is the set of Unicode characters in script Coptic. Cuneiform = _Cuneiform // Cuneiform is the set of Unicode characters in script Cuneiform. Cypriot = _Cypriot // Cypriot is the set of Unicode characters in script Cypriot. + Cypro_Minoan = _Cypro_Minoan // Cypro_Minoan is the set of Unicode characters in script Cypro_Minoan. Cyrillic = _Cyrillic // Cyrillic is the set of Unicode characters in script Cyrillic. Deseret = _Deseret // Deseret is the set of Unicode characters in script Deseret. Devanagari = _Devanagari // Devanagari is the set of Unicode characters in script Devanagari. @@ -5644,6 +5892,7 @@ var ( Kaithi = _Kaithi // Kaithi is the set of Unicode characters in script Kaithi. Kannada = _Kannada // Kannada is the set of Unicode characters in script Kannada. Katakana = _Katakana // Katakana is the set of Unicode characters in script Katakana. + Kawi = _Kawi // Kawi is the set of Unicode characters in script Kawi. Kayah_Li = _Kayah_Li // Kayah_Li is the set of Unicode characters in script Kayah_Li. Kharoshthi = _Kharoshthi // Kharoshthi is the set of Unicode characters in script Kharoshthi. Khitan_Small_Script = _Khitan_Small_Script // Khitan_Small_Script is the set of Unicode characters in script Khitan_Small_Script. @@ -5678,6 +5927,7 @@ var ( Multani = _Multani // Multani is the set of Unicode characters in script Multani. Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar. Nabataean = _Nabataean // Nabataean is the set of Unicode characters in script Nabataean. + Nag_Mundari = _Nag_Mundari // Nag_Mundari is the set of Unicode characters in script Nag_Mundari. Nandinagari = _Nandinagari // Nandinagari is the set of Unicode characters in script Nandinagari. New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue. Newa = _Newa // Newa is the set of Unicode characters in script Newa. @@ -5694,6 +5944,7 @@ var ( Old_Sogdian = _Old_Sogdian // Old_Sogdian is the set of Unicode characters in script Old_Sogdian. Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian. Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic. + Old_Uyghur = _Old_Uyghur // Old_Uyghur is the set of Unicode characters in script Old_Uyghur. Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya. Osage = _Osage // Osage is the set of Unicode characters in script Osage. Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya. @@ -5725,6 +5976,7 @@ var ( Tai_Viet = _Tai_Viet // Tai_Viet is the set of Unicode characters in script Tai_Viet. Takri = _Takri // Takri is the set of Unicode characters in script Takri. Tamil = _Tamil // Tamil is the set of Unicode characters in script Tamil. + Tangsa = _Tangsa // Tangsa is the set of Unicode characters in script Tangsa. Tangut = _Tangut // Tangut is the set of Unicode characters in script Tangut. Telugu = _Telugu // Telugu is the set of Unicode characters in script Telugu. Thaana = _Thaana // Thaana is the set of Unicode characters in script Thaana. @@ -5732,8 +5984,10 @@ var ( Tibetan = _Tibetan // Tibetan is the set of Unicode characters in script Tibetan. Tifinagh = _Tifinagh // Tifinagh is the set of Unicode characters in script Tifinagh. Tirhuta = _Tirhuta // Tirhuta is the set of Unicode characters in script Tirhuta. + Toto = _Toto // Toto is the set of Unicode characters in script Toto. Ugaritic = _Ugaritic // Ugaritic is the set of Unicode characters in script Ugaritic. Vai = _Vai // Vai is the set of Unicode characters in script Vai. + Vithkuqi = _Vithkuqi // Vithkuqi is the set of Unicode characters in script Vithkuqi. Wancho = _Wancho // Wancho is the set of Unicode characters in script Wancho. Warang_Citi = _Warang_Citi // Warang_Citi is the set of Unicode characters in script Warang_Citi. Yezidi = _Yezidi // Yezidi is the set of Unicode characters in script Yezidi. @@ -5808,11 +6062,11 @@ var _Dash = &RangeTable{ {0x208b, 0x2212, 391}, {0x2e17, 0x2e1a, 3}, {0x2e3a, 0x2e3b, 1}, - {0x2e40, 0x301c, 476}, - {0x3030, 0x30a0, 112}, - {0xfe31, 0xfe32, 1}, - {0xfe58, 0xfe63, 11}, - {0xff0d, 0xff0d, 1}, + {0x2e40, 0x2e5d, 29}, + {0x301c, 0x3030, 20}, + {0x30a0, 0xfe31, 52625}, + {0xfe32, 0xfe58, 38}, + {0xfe63, 0xff0d, 170}, }, R32: []Range32{ {0x10ead, 0x10ead, 1}, @@ -5859,6 +6113,8 @@ var _Diacritic = &RangeTable{ {0x07a6, 0x07b0, 1}, {0x07eb, 0x07f5, 1}, {0x0818, 0x0819, 1}, + {0x0898, 0x089f, 1}, + {0x08c9, 0x08d2, 1}, {0x08e3, 0x08fe, 1}, {0x093c, 0x094d, 17}, {0x0951, 0x0954, 1}, @@ -5869,10 +6125,10 @@ var _Diacritic = &RangeTable{ {0x0afe, 0x0aff, 1}, {0x0b3c, 0x0b4d, 17}, {0x0b55, 0x0bcd, 120}, - {0x0c4d, 0x0cbc, 111}, - {0x0ccd, 0x0d3b, 110}, - {0x0d3c, 0x0d4d, 17}, - {0x0dca, 0x0e47, 125}, + {0x0c3c, 0x0c4d, 17}, + {0x0cbc, 0x0ccd, 17}, + {0x0d3b, 0x0d3c, 1}, + {0x0d4d, 0x0e47, 125}, {0x0e48, 0x0e4c, 1}, {0x0e4e, 0x0eba, 108}, {0x0ec8, 0x0ecc, 1}, @@ -5889,12 +6145,14 @@ var _Diacritic = &RangeTable{ {0x108f, 0x109a, 11}, {0x109b, 0x135d, 706}, {0x135e, 0x135f, 1}, + {0x1714, 0x1715, 1}, {0x17c9, 0x17d3, 1}, {0x17dd, 0x1939, 348}, {0x193a, 0x193b, 1}, {0x1a75, 0x1a7c, 1}, {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1abd, 1}, + {0x1ab1, 0x1abe, 1}, + {0x1ac1, 0x1acb, 1}, {0x1b34, 0x1b44, 16}, {0x1b6b, 0x1b73, 1}, {0x1baa, 0x1bab, 1}, @@ -5905,8 +6163,7 @@ var _Diacritic = &RangeTable{ {0x1cf7, 0x1cf9, 1}, {0x1d2c, 0x1d6a, 1}, {0x1dc4, 0x1dcf, 1}, - {0x1df5, 0x1df9, 1}, - {0x1dfd, 0x1dff, 1}, + {0x1df5, 0x1dff, 1}, {0x1fbd, 0x1fbf, 2}, {0x1fc0, 0x1fc1, 1}, {0x1fcd, 0x1fcf, 1}, @@ -5943,10 +6200,16 @@ var _Diacritic = &RangeTable{ {0xff9f, 0xffe3, 68}, }, R32: []Range32{ - {0x102e0, 0x10ae5, 2053}, - {0x10ae6, 0x10d22, 572}, - {0x10d23, 0x10d27, 1}, + {0x102e0, 0x10780, 1184}, + {0x10781, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x10ae5, 0x10ae6, 1}, + {0x10d22, 0x10d27, 1}, + {0x10efd, 0x10eff, 1}, {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, + {0x11046, 0x11070, 42}, {0x110b9, 0x110ba, 1}, {0x11133, 0x11134, 1}, {0x11173, 0x111c0, 77}, @@ -5968,17 +6231,25 @@ var _Diacritic = &RangeTable{ {0x11a99, 0x11c3f, 422}, {0x11d42, 0x11d44, 2}, {0x11d45, 0x11d97, 82}, + {0x13447, 0x13455, 1}, {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f8f, 0x16f9f, 1}, {0x16ff0, 0x16ff1, 1}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1cf00, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, {0x1d167, 0x1d169, 1}, {0x1d16d, 0x1d172, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, + {0x1e030, 0x1e06d, 1}, {0x1e130, 0x1e136, 1}, - {0x1e2ec, 0x1e2ef, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, {0x1e8d0, 0x1e8d6, 1}, {0x1e944, 0x1e946, 1}, {0x1e948, 0x1e94a, 1}, @@ -6005,6 +6276,7 @@ var _Extender = &RangeTable{ {0xff70, 0xff70, 1}, }, R32: []Range32{ + {0x10781, 0x10782, 1}, {0x1135d, 0x115c6, 617}, {0x115c7, 0x115c8, 1}, {0x11a98, 0x16b42, 20650}, @@ -6058,7 +6330,7 @@ var _Ideographic = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303a, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, + {0x4e00, 0x9fff, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, @@ -6068,13 +6340,14 @@ var _Ideographic = &RangeTable{ {0x18800, 0x18cd5, 1}, {0x18d00, 0x18d08, 1}, {0x1b170, 0x1b2fb, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, } @@ -6178,7 +6451,7 @@ var _Other_Alphabetic = &RangeTable{ {0x0bc6, 0x0bc8, 1}, {0x0bca, 0x0bcc, 1}, {0x0bd7, 0x0c00, 41}, - {0x0c01, 0x0c03, 1}, + {0x0c01, 0x0c04, 1}, {0x0c3e, 0x0c44, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4c, 1}, @@ -6190,7 +6463,8 @@ var _Other_Alphabetic = &RangeTable{ {0x0cca, 0x0ccc, 1}, {0x0cd5, 0x0cd6, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d00, 0x0d03, 1}, + {0x0cf3, 0x0d00, 13}, + {0x0d01, 0x0d03, 1}, {0x0d3e, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4c, 1}, @@ -6207,7 +6481,7 @@ var _Other_Alphabetic = &RangeTable{ {0x0eb4, 0x0eb9, 1}, {0x0ebb, 0x0ebc, 1}, {0x0ecd, 0x0f71, 164}, - {0x0f72, 0x0f81, 1}, + {0x0f72, 0x0f83, 1}, {0x0f8d, 0x0f97, 1}, {0x0f99, 0x0fbc, 1}, {0x102b, 0x1036, 1}, @@ -6234,6 +6508,7 @@ var _Other_Alphabetic = &RangeTable{ {0x1a55, 0x1a5e, 1}, {0x1a61, 0x1a74, 1}, {0x1abf, 0x1ac0, 1}, + {0x1acc, 0x1ace, 1}, {0x1b00, 0x1b04, 1}, {0x1b35, 0x1b43, 1}, {0x1b80, 0x1b82, 1}, @@ -6278,9 +6553,11 @@ var _Other_Alphabetic = &RangeTable{ {0x10eab, 0x10eac, 1}, {0x11000, 0x11002, 1}, {0x11038, 0x11045, 1}, - {0x11082, 0x110b0, 46}, - {0x110b1, 0x110b8, 1}, - {0x11100, 0x11102, 1}, + {0x11073, 0x11074, 1}, + {0x11080, 0x11082, 1}, + {0x110b0, 0x110b8, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, {0x11127, 0x11132, 1}, {0x11145, 0x11146, 1}, {0x11180, 0x11182, 1}, @@ -6288,7 +6565,8 @@ var _Other_Alphabetic = &RangeTable{ {0x111ce, 0x111cf, 1}, {0x1122c, 0x11234, 1}, {0x11237, 0x1123e, 7}, - {0x112df, 0x112e8, 1}, + {0x11241, 0x112df, 158}, + {0x112e0, 0x112e8, 1}, {0x11300, 0x11303, 1}, {0x1133e, 0x11344, 1}, {0x11347, 0x11348, 1}, @@ -6331,6 +6609,10 @@ var _Other_Alphabetic = &RangeTable{ {0x11d90, 0x11d91, 1}, {0x11d93, 0x11d96, 1}, {0x11ef3, 0x11ef6, 1}, + {0x11f00, 0x11f01, 1}, + {0x11f03, 0x11f34, 49}, + {0x11f35, 0x11f3a, 1}, + {0x11f3e, 0x11f40, 1}, {0x16f4f, 0x16f51, 2}, {0x16f52, 0x16f87, 1}, {0x16f8f, 0x16f92, 1}, @@ -6341,8 +6623,8 @@ var _Other_Alphabetic = &RangeTable{ {0x1e01b, 0x1e021, 1}, {0x1e023, 0x1e024, 1}, {0x1e026, 0x1e02a, 1}, - {0x1e947, 0x1f130, 2025}, - {0x1f131, 0x1f149, 1}, + {0x1e08f, 0x1e947, 2232}, + {0x1f130, 0x1f149, 1}, {0x1f150, 0x1f169, 1}, {0x1f170, 0x1f189, 1}, }, @@ -6410,7 +6692,8 @@ var _Other_Lowercase = &RangeTable{ {0x02c0, 0x02c1, 1}, {0x02e0, 0x02e4, 1}, {0x0345, 0x037a, 53}, - {0x1d2c, 0x1d6a, 1}, + {0x10fc, 0x1d2c, 3120}, + {0x1d2d, 0x1d6a, 1}, {0x1d78, 0x1d9b, 35}, {0x1d9c, 0x1dbf, 1}, {0x2071, 0x207f, 14}, @@ -6419,9 +6702,18 @@ var _Other_Lowercase = &RangeTable{ {0x24d0, 0x24e9, 1}, {0x2c7c, 0x2c7d, 1}, {0xa69c, 0xa69d, 1}, - {0xa770, 0xa7f8, 136}, - {0xa7f9, 0xab5c, 867}, - {0xab5d, 0xab5f, 1}, + {0xa770, 0xa7f2, 130}, + {0xa7f3, 0xa7f4, 1}, + {0xa7f8, 0xa7f9, 1}, + {0xab5c, 0xab5f, 1}, + {0xab69, 0xab69, 1}, + }, + R32: []Range32{ + {0x10780, 0x10783, 3}, + {0x10784, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x1e030, 0x1e06d, 1}, }, LatinOffset: 1, } @@ -6607,6 +6899,7 @@ var _Prepended_Concatenation_Mark = &RangeTable{ R16: []Range16{ {0x0600, 0x0605, 1}, {0x06dd, 0x070f, 50}, + {0x0890, 0x0891, 1}, {0x08e2, 0x08e2, 1}, }, R32: []Range32{ @@ -6649,7 +6942,7 @@ var _Sentence_Terminal = &RangeTable{ R16: []Range16{ {0x0021, 0x002e, 13}, {0x003f, 0x0589, 1354}, - {0x061e, 0x061f, 1}, + {0x061d, 0x061f, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x0702, 1}, {0x07f9, 0x0837, 62}, @@ -6665,11 +6958,13 @@ var _Sentence_Terminal = &RangeTable{ {0x1aa9, 0x1aab, 1}, {0x1b5a, 0x1b5b, 1}, {0x1b5e, 0x1b5f, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1c3b, 0x1c3c, 1}, {0x1c7e, 0x1c7f, 1}, {0x203c, 0x203d, 1}, {0x2047, 0x2049, 1}, {0x2e2e, 0x2e3c, 14}, + {0x2e53, 0x2e54, 1}, {0x3002, 0xa4ff, 29949}, {0xa60e, 0xa60f, 1}, {0xa6f3, 0xa6f7, 4}, @@ -6687,6 +6982,7 @@ var _Sentence_Terminal = &RangeTable{ R32: []Range32{ {0x10a56, 0x10a57, 1}, {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x11048, 1}, {0x110be, 0x110c1, 1}, {0x11141, 0x11143, 1}, @@ -6705,6 +7001,7 @@ var _Sentence_Terminal = &RangeTable{ {0x11a9b, 0x11a9c, 1}, {0x11c41, 0x11c42, 1}, {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f44, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b44, 12}, @@ -6741,6 +7038,8 @@ var _Soft_Dotted = &RangeTable{ {0x1d62a, 0x1d62b, 1}, {0x1d65e, 0x1d65f, 1}, {0x1d692, 0x1d693, 1}, + {0x1df1a, 0x1e04c, 306}, + {0x1e04d, 0x1e068, 27}, }, LatinOffset: 1, } @@ -6753,7 +7052,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x037e, 0x0387, 9}, {0x0589, 0x05c3, 58}, {0x060c, 0x061b, 15}, - {0x061e, 0x061f, 1}, + {0x061d, 0x061f, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x070a, 1}, {0x070c, 0x07f8, 236}, @@ -6776,6 +7075,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x1aa8, 0x1aab, 1}, {0x1b5a, 0x1b5b, 1}, {0x1b5d, 0x1b5f, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, {0x203c, 0x203d, 1}, @@ -6783,6 +7083,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x2e2e, 0x2e3c, 14}, {0x2e41, 0x2e4c, 11}, {0x2e4e, 0x2e4f, 1}, + {0x2e53, 0x2e54, 1}, {0x3001, 0x3002, 1}, {0xa4fe, 0xa4ff, 1}, {0xa60d, 0xa60f, 1}, @@ -6809,6 +7110,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x10b3a, 0x10b3f, 1}, {0x10b99, 0x10b9c, 1}, {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x1104d, 1}, {0x110be, 0x110c1, 1}, {0x11141, 0x11143, 1}, @@ -6829,7 +7131,8 @@ var _Terminal_Punctuation = &RangeTable{ {0x11aa1, 0x11aa2, 1}, {0x11c41, 0x11c43, 1}, {0x11c71, 0x11ef7, 646}, - {0x11ef8, 0x12470, 1400}, + {0x11ef8, 0x11f43, 75}, + {0x11f44, 0x12470, 1324}, {0x12471, 0x12474, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, @@ -6844,7 +7147,7 @@ var _Terminal_Punctuation = &RangeTable{ var _Unified_Ideograph = &RangeTable{ R16: []Range16{ {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, + {0x4e00, 0x9fff, 1}, {0xfa0e, 0xfa0f, 1}, {0xfa11, 0xfa13, 2}, {0xfa14, 0xfa1f, 11}, @@ -6853,19 +7156,21 @@ var _Unified_Ideograph = &RangeTable{ {0xfa28, 0xfa29, 1}, }, R32: []Range32{ - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, } var _Variation_Selector = &RangeTable{ R16: []Range16{ {0x180b, 0x180d, 1}, - {0xfe00, 0xfe0f, 1}, + {0x180f, 0xfe00, 58865}, + {0xfe01, 0xfe0f, 1}, }, R32: []Range32{ {0xe0100, 0xe01ef, 1}, @@ -7182,8 +7487,8 @@ var _CaseRanges = []CaseRange{ {0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}}, {0x24B6, 0x24CF, d{0, 26, 0}}, {0x24D0, 0x24E9, d{-26, 0, -26}}, - {0x2C00, 0x2C2E, d{0, 48, 0}}, - {0x2C30, 0x2C5E, d{-48, 0, -48}}, + {0x2C00, 0x2C2F, d{0, 48, 0}}, + {0x2C30, 0x2C5F, d{-48, 0, -48}}, {0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}}, {0x2C62, 0x2C62, d{0, -10743, 0}}, {0x2C63, 0x2C63, d{0, -3814, 0}}, @@ -7225,12 +7530,13 @@ var _CaseRanges = []CaseRange{ {0xA7B1, 0xA7B1, d{0, -42282, 0}}, {0xA7B2, 0xA7B2, d{0, -42261, 0}}, {0xA7B3, 0xA7B3, d{0, 928, 0}}, - {0xA7B4, 0xA7BF, d{UpperLower, UpperLower, UpperLower}}, - {0xA7C2, 0xA7C3, d{UpperLower, UpperLower, UpperLower}}, + {0xA7B4, 0xA7C3, d{UpperLower, UpperLower, UpperLower}}, {0xA7C4, 0xA7C4, d{0, -48, 0}}, {0xA7C5, 0xA7C5, d{0, -42307, 0}}, {0xA7C6, 0xA7C6, d{0, -35384, 0}}, {0xA7C7, 0xA7CA, d{UpperLower, UpperLower, UpperLower}}, + {0xA7D0, 0xA7D1, d{UpperLower, UpperLower, UpperLower}}, + {0xA7D6, 0xA7D9, d{UpperLower, UpperLower, UpperLower}}, {0xA7F5, 0xA7F6, d{UpperLower, UpperLower, UpperLower}}, {0xAB53, 0xAB53, d{-928, 0, -928}}, {0xAB70, 0xABBF, d{-38864, 0, -38864}}, @@ -7240,6 +7546,14 @@ var _CaseRanges = []CaseRange{ {0x10428, 0x1044F, d{-40, 0, -40}}, {0x104B0, 0x104D3, d{0, 40, 0}}, {0x104D8, 0x104FB, d{-40, 0, -40}}, + {0x10570, 0x1057A, d{0, 39, 0}}, + {0x1057C, 0x1058A, d{0, 39, 0}}, + {0x1058C, 0x10592, d{0, 39, 0}}, + {0x10594, 0x10595, d{0, 39, 0}}, + {0x10597, 0x105A1, d{-39, 0, -39}}, + {0x105A3, 0x105B1, d{-39, 0, -39}}, + {0x105B3, 0x105B9, d{-39, 0, -39}}, + {0x105BB, 0x105BC, d{-39, 0, -39}}, {0x10C80, 0x10CB2, d{0, 64, 0}}, {0x10CC0, 0x10CF2, d{-64, 0, -64}}, {0x118A0, 0x118BF, d{0, 32, 0}}, @@ -7378,7 +7692,7 @@ var properties = [MaxLatin1 + 1]uint8{ 0x7C: pS | pp, // '|' 0x7D: pP | pp, // '}' 0x7E: pS | pp, // '~' - 0x7F: pC, // '\u007f' + 0x7F: pC, // '\x7f' 0x80: pC, // '\u0080' 0x81: pC, // '\u0081' 0x82: pC, // '\u0082' @@ -7833,7 +8147,7 @@ var foldLl = &RangeTable{ {0x2126, 0x212a, 4}, {0x212b, 0x2132, 7}, {0x2183, 0x2c00, 2685}, - {0x2c01, 0x2c2e, 1}, + {0x2c01, 0x2c2f, 1}, {0x2c60, 0x2c62, 2}, {0x2c63, 0x2c64, 1}, {0x2c67, 0x2c6d, 2}, @@ -7854,15 +8168,20 @@ var foldLl = &RangeTable{ {0xa796, 0xa7aa, 2}, {0xa7ab, 0xa7ae, 1}, {0xa7b0, 0xa7b4, 1}, - {0xa7b6, 0xa7be, 2}, - {0xa7c2, 0xa7c4, 2}, + {0xa7b6, 0xa7c4, 2}, {0xa7c5, 0xa7c7, 1}, - {0xa7c9, 0xa7f5, 44}, - {0xff21, 0xff3a, 1}, + {0xa7c9, 0xa7d0, 7}, + {0xa7d6, 0xa7d8, 2}, + {0xa7f5, 0xff21, 22316}, + {0xff22, 0xff3a, 1}, }, R32: []Range32{ {0x10400, 0x10427, 1}, {0x104b0, 0x104d3, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, {0x10c80, 0x10cb2, 1}, {0x118a0, 0x118bf, 1}, {0x16e40, 0x16e5f, 1}, @@ -7971,7 +8290,7 @@ var foldLu = &RangeTable{ {0x1fd1, 0x1fe0, 15}, {0x1fe1, 0x1fe5, 4}, {0x214e, 0x2184, 54}, - {0x2c30, 0x2c5e, 1}, + {0x2c30, 0x2c5f, 1}, {0x2c61, 0x2c65, 4}, {0x2c66, 0x2c6c, 2}, {0x2c73, 0x2c76, 3}, @@ -7989,9 +8308,10 @@ var foldLu = &RangeTable{ {0xa78c, 0xa791, 5}, {0xa793, 0xa794, 1}, {0xa797, 0xa7a9, 2}, - {0xa7b5, 0xa7bf, 2}, - {0xa7c3, 0xa7c8, 5}, - {0xa7ca, 0xa7f6, 44}, + {0xa7b5, 0xa7c3, 2}, + {0xa7c8, 0xa7ca, 2}, + {0xa7d1, 0xa7d7, 6}, + {0xa7d9, 0xa7f6, 29}, {0xab53, 0xab70, 29}, {0xab71, 0xabbf, 1}, {0xff41, 0xff5a, 1}, @@ -7999,6 +8319,10 @@ var foldLu = &RangeTable{ R32: []Range32{ {0x10428, 0x1044f, 1}, {0x104d8, 0x104fb, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, {0x10cc0, 0x10cf2, 1}, {0x118c0, 0x118df, 1}, {0x16e60, 0x16e7f, 1}, @@ -8050,7 +8374,7 @@ var foldInherited = &RangeTable{ }, } -// Range entries: 3499 16-bit, 1820 32-bit, 5319 total. -// Range bytes: 20994 16-bit, 21840 32-bit, 42834 total. +// Range entries: 3535 16-bit, 2031 32-bit, 5566 total. +// Range bytes: 21210 16-bit, 24372 32-bit, 45582 total. // Fold orbit bytes: 88 pairs, 352 bytes diff --git a/gnovm/stdlibs/unicode/utf8/example_test.gno b/gnovm/stdlibs/unicode/utf8/example_test.gno index 17d6e8d2114..fe434c94767 100644 --- a/gnovm/stdlibs/unicode/utf8/example_test.gno +++ b/gnovm/stdlibs/unicode/utf8/example_test.gno @@ -49,6 +49,7 @@ func ExampleDecodeLastRuneInString() { // l 1 // e 1 // H 1 + } func ExampleDecodeRune() { @@ -213,3 +214,13 @@ func ExampleValidString() { // true // false } + +func ExampleAppendRune() { + buf1 := utf8.AppendRune(nil, 0x10000) + buf2 := utf8.AppendRune([]byte("init"), 0x10000) + fmt.Println(string(buf1)) + fmt.Println(string(buf2)) + // Output: + // 𐀀 + // init𐀀 +} diff --git a/gnovm/stdlibs/unicode/utf8/utf8.gno b/gnovm/stdlibs/unicode/utf8/utf8.gno index 9c70281488d..71d6bf18d01 100644 --- a/gnovm/stdlibs/unicode/utf8/utf8.gno +++ b/gnovm/stdlibs/unicode/utf8/utf8.gno @@ -141,7 +141,7 @@ func FullRuneInString(s string) bool { } // DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and -// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if +// its width in bytes. If p is empty it returns ([RuneError], 0). Otherwise, if // the encoding is invalid, it returns (RuneError, 1). Both are impossible // results for correct, non-empty UTF-8. // @@ -188,8 +188,8 @@ func DecodeRune(p []byte) (r rune, size int) { return rune(p0&mask4)<<18 | rune(b1&maskx)<<12 | rune(b2&maskx)<<6 | rune(b3&maskx), 4 } -// DecodeRuneInString is like DecodeRune but its input is a string. If s is -// empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, it +// DecodeRuneInString is like [DecodeRune] but its input is a string. If s is +// empty it returns ([RuneError], 0). Otherwise, if the encoding is invalid, it // returns (RuneError, 1). Both are impossible results for correct, non-empty // UTF-8. // @@ -237,7 +237,7 @@ func DecodeRuneInString(s string) (r rune, size int) { } // DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and -// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if +// its width in bytes. If p is empty it returns ([RuneError], 0). Otherwise, if // the encoding is invalid, it returns (RuneError, 1). Both are impossible // results for correct, non-empty UTF-8. // @@ -276,8 +276,8 @@ func DecodeLastRune(p []byte) (r rune, size int) { return r, size } -// DecodeLastRuneInString is like DecodeLastRune but its input is a string. If -// s is empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, +// DecodeLastRuneInString is like [DecodeLastRune] but its input is a string. If +// s is empty it returns ([RuneError], 0). Otherwise, if the encoding is invalid, // it returns (RuneError, 1). Both are impossible results for correct, // non-empty UTF-8. // @@ -337,7 +337,7 @@ func RuneLen(r rune) int { } // EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune. -// If the rune is out of range, it writes the encoding of RuneError. +// If the rune is out of range, it writes the encoding of [RuneError]. // It returns the number of bytes written. func EncodeRune(p []byte, r rune) int { // Negative values are erroneous. Making it unsigned addresses the problem. @@ -352,13 +352,7 @@ func EncodeRune(p []byte, r rune) int { return 2 case i > MaxRune, surrogateMin <= i && i <= surrogateMax: r = RuneError - // XXX fallthrough not implemented - // fallthrough - _ = p[2] // eliminate bounds checks - p[0] = t3 | byte(r>>12) - p[1] = tx | byte(r>>6)&maskx - p[2] = tx | byte(r)&maskx - return 3 + fallthrough case i <= rune3Max: _ = p[2] // eliminate bounds checks p[0] = t3 | byte(r>>12) @@ -375,6 +369,32 @@ func EncodeRune(p []byte, r rune) int { } } +// AppendRune appends the UTF-8 encoding of r to the end of p and +// returns the extended buffer. If the rune is out of range, +// it appends the encoding of [RuneError]. +func AppendRune(p []byte, r rune) []byte { + // This function is inlineable for fast handling of ASCII. + if uint32(r) <= rune1Max { + return append(p, byte(r)) + } + return appendRuneNonASCII(p, r) +} + +func appendRuneNonASCII(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune2Max: + return append(p, t2|byte(r>>6), tx|byte(r)&maskx) + case i > MaxRune, surrogateMin <= i && i <= surrogateMax: + r = RuneError + fallthrough + case i <= rune3Max: + return append(p, t3|byte(r>>12), tx|byte(r>>6)&maskx, tx|byte(r)&maskx) + default: + return append(p, t4|byte(r>>18), tx|byte(r>>12)&maskx, tx|byte(r>>6)&maskx, tx|byte(r)&maskx) + } +} + // RuneCount returns the number of runes in p. Erroneous and short // encodings are treated as single runes of width 1 byte. func RuneCount(p []byte) int { @@ -413,7 +433,7 @@ func RuneCount(p []byte) int { return n } -// RuneCountInString is like RuneCount but its input is a string. +// RuneCountInString is like [RuneCount] but its input is a string. func RuneCountInString(s string) (n int) { ns := len(s) for i := 0; i < ns; n++ { @@ -455,6 +475,11 @@ func RuneStart(b byte) bool { return b&0xC0 != 0x80 } // Valid reports whether p consists entirely of valid UTF-8-encoded runes. func Valid(p []byte) bool { + // This optimization avoids the need to recompute the capacity + // when generating code for p[8:], bringing it to parity with + // ValidString, which was 20% faster on long ASCII strings. + p = p[:len(p):len(p)] + // Fast path. Check for and skip 8 bytes of ASCII characters per iteration. for len(p) >= 8 { // Combining two 32 bit loads allows the same code to be used diff --git a/gnovm/stdlibs/unicode/utf8/utf8_test.gno b/gnovm/stdlibs/unicode/utf8/utf8_test.gno index 7fecb778975..0384b7a88e9 100644 --- a/gnovm/stdlibs/unicode/utf8/utf8_test.gno +++ b/gnovm/stdlibs/unicode/utf8/utf8_test.gno @@ -127,6 +127,17 @@ func TestEncodeRune(t *testing.T) { } } +func TestAppendRune(t *testing.T) { + for _, m := range utf8map { + if buf := utf8.AppendRune(nil, m.r); string(buf) != m.str { + t.Errorf("AppendRune(nil, %#04x) = %s, want %s", m.r, buf, m.str) + } + if buf := utf8.AppendRune([]byte("init"), m.r); string(buf) != "init"+m.str { + t.Errorf("AppendRune(init, %#04x) = %s, want %s", m.r, buf, "init"+m.str) + } + } +} + func TestDecodeRune(t *testing.T) { for _, m := range utf8map { b := []byte(m.str) diff --git a/gnovm/tests/files/break0.gno b/gnovm/tests/files/break0.gno new file mode 100644 index 00000000000..17d68dc1dbf --- /dev/null +++ b/gnovm/tests/files/break0.gno @@ -0,0 +1,8 @@ +package main + +func main() { + break +} + +// Error: +// main/files/break0.gno:4:2: cannot break with no parent loop or switch diff --git a/gnovm/tests/files/cont3.gno b/gnovm/tests/files/cont3.gno new file mode 100644 index 00000000000..8a305d4ceb2 --- /dev/null +++ b/gnovm/tests/files/cont3.gno @@ -0,0 +1,8 @@ +package main + +func main() { + continue +} + +// Error: +// main/files/cont3.gno:4:2: cannot continue with no parent loop diff --git a/gnovm/tests/files/for20.gno b/gnovm/tests/files/for20.gno new file mode 100644 index 00000000000..ad9f1f124d0 --- /dev/null +++ b/gnovm/tests/files/for20.gno @@ -0,0 +1,15 @@ +package main + +func main() { + // Ensure `break` works also when we have a label for the for loop. + +loop: + for { + break + } + + println("hey") +} + +// Output: +// hey diff --git a/gnovm/tests/files/redeclaration10.gno b/gnovm/tests/files/redeclaration10.gno index 01584b1755c..afbf3c6a607 100644 --- a/gnovm/tests/files/redeclaration10.gno +++ b/gnovm/tests/files/redeclaration10.gno @@ -6,7 +6,5 @@ func main() { println("should not happen") } -// XXX show what was redeclared. - // Error: -// running package "github.com/gnolang/gno/_test/redeclaration3": duplicate declarations not allowed +// running package "github.com/gnolang/gno/_test/redeclaration3": redeclarations for identifiers: "a.method" diff --git a/gnovm/tests/files/redeclaration6.gno b/gnovm/tests/files/redeclaration6.gno index 25e36fa61aa..74e762604ba 100644 --- a/gnovm/tests/files/redeclaration6.gno +++ b/gnovm/tests/files/redeclaration6.gno @@ -6,7 +6,5 @@ func main() { println("should not happen") } -// XXX show what was redeclared. - // Error: -// running package "github.com/gnolang/gno/_test/redeclaration1": duplicate declarations not allowed +// running package "github.com/gnolang/gno/_test/redeclaration1": redeclarations for identifiers: "a" diff --git a/gnovm/tests/files/redeclaration8.gno b/gnovm/tests/files/redeclaration8.gno index d0e5b958030..51c8871a4f2 100644 --- a/gnovm/tests/files/redeclaration8.gno +++ b/gnovm/tests/files/redeclaration8.gno @@ -6,7 +6,5 @@ func main() { println("should not happen") } -// XXX show what was redeclared. - // Error: -// running package "github.com/gnolang/gno/_test/redeclaration2": duplicate declarations not allowed +// running package "github.com/gnolang/gno/_test/redeclaration2": redeclarations for identifiers: "a" diff --git a/gnovm/tests/imports.go b/gnovm/tests/imports.go index 30f410fa8d5..b8532253ce3 100644 --- a/gnovm/tests/imports.go +++ b/gnovm/tests/imports.go @@ -246,6 +246,15 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf(time.Month(0))) pkg.DefineGoNativeValue("LoadLocation", time.LoadLocation) return pkg, pkg.NewPackage() + case "strconv": + pkg := gno.NewPackageNode("strconv", pkgPath, nil) + pkg.DefineGoNativeValue("Itoa", strconv.Itoa) + pkg.DefineGoNativeValue("Atoi", strconv.Atoi) + pkg.DefineGoNativeValue("ParseInt", strconv.ParseInt) + pkg.DefineGoNativeValue("Quote", strconv.Quote) + pkg.DefineGoNativeValue("FormatUint", strconv.FormatUint) + pkg.DefineGoNativeType(reflect.TypeOf(strconv.NumError{})) + return pkg, pkg.NewPackage() case "strings": pkg := gno.NewPackageNode("strings", pkgPath, nil) pkg.DefineGoNativeValue("Split", strings.Split) @@ -418,7 +427,6 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri resStore = gno.NewStore(nil, baseStore, iavlStore) resStore.SetPackageGetter(getPackage) resStore.SetNativeStore(teststdlibs.NativeStore) - resStore.SetPackageInjector(testPackageInjector) resStore.SetStrictGo2GnoMapping(false) return } @@ -465,19 +473,6 @@ func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer) (*gn return m2.RunMemPackageWithOverrides(memPkg, save) } -func testPackageInjector(store gno.Store, pn *gno.PackageNode) { - // Test specific injections: - switch pn.PkgPath { - case "strconv": - // NOTE: Itoa and Atoi are already injected - // from stdlibs.InjectNatives. - pn.DefineGoNativeType(reflect.TypeOf(strconv.NumError{})) - pn.DefineGoNativeValue("ParseInt", strconv.ParseInt) - } -} - -// ---------------------------------------- - type dummyReader struct{} func (*dummyReader) Read(b []byte) (n int, err error) { From 5ef7cbf7dfabdac141f8ea6413a6c57e331a752e Mon Sep 17 00:00:00 2001 From: Malek Lahbib <111009238+MalekLahbib@users.noreply.github.com> Date: Fri, 18 Oct 2024 11:49:00 +0200 Subject: [PATCH 15/64] docs: add `gno {env,fmt}` to go-gno-compatibility (#2974) gno env and gno fmt missing in the docs.
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- docs/reference/go-gno-compatibility.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/go-gno-compatibility.md b/docs/reference/go-gno-compatibility.md index f73ff33cce7..9f9d611e4fd 100644 --- a/docs/reference/go-gno-compatibility.md +++ b/docs/reference/go-gno-compatibility.md @@ -303,9 +303,9 @@ Legend: | go build | gno transpile -gobuild | same intention, limited compatibility | | go clean | gno clean | same intention, limited compatibility | | go doc | gno doc | limited compatibility; see https://github.com/gnolang/gno/issues/522 | -| go env | | | +| go env | gno env | | | go fix | | | -| go fmt | | gofmt (& similar tools, like gofumpt) works on gno code. | +| go fmt | gno fmt | gofmt (& similar tools, like gofumpt) works on gno code. | | go generate | | | | go get | | see `gno mod download`. | | go help | gno $cmd --help | ie. `gno doc --help` | From e58716763ee42631fd0556d03807b8137ff527b0 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Fri, 18 Oct 2024 15:49:51 +0200 Subject: [PATCH 16/64] chore: Run stdlib tests in parallel to make gnovm tests run faster (#2864) Check https://github.com/gnolang/gno/issues/2826 for more context. --------- Signed-off-by: Antonio Navarro --- gnovm/tests/package_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnovm/tests/package_test.go b/gnovm/tests/package_test.go index 8e497941c7f..d4ddfc9a4f0 100644 --- a/gnovm/tests/package_test.go +++ b/gnovm/tests/package_test.go @@ -16,6 +16,8 @@ import ( ) func TestStdlibs(t *testing.T) { + t.Parallel() + // NOTE: this test only works using _test.gno files; // filetests are not meant to be used for testing standard libraries. // The examples directory is tested directly using `gno test`u @@ -51,6 +53,8 @@ func TestStdlibs(t *testing.T) { for _, pkgPath := range pkgPaths { testDir := testDirs[pkgPath] t.Run(pkgPath, func(t *testing.T) { + pkgPath := pkgPath + t.Parallel() runPackageTest(t, testDir, pkgPath) }) } From 4d86229092d5f0480080d8f1cb22edd150b84768 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Fri, 18 Oct 2024 17:42:51 +0200 Subject: [PATCH 17/64] fix(gnovm): remove migration code of old GNOHOME (#2978) closes #800
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- gnovm/pkg/gnoenv/gnohome.go | 2 -- gnovm/pkg/gnoenv/migration.go | 28 ---------------------------- gnovm/pkg/gnoenv/migration_test.go | 29 ----------------------------- 3 files changed, 59 deletions(-) delete mode 100644 gnovm/pkg/gnoenv/migration.go delete mode 100644 gnovm/pkg/gnoenv/migration_test.go diff --git a/gnovm/pkg/gnoenv/gnohome.go b/gnovm/pkg/gnoenv/gnohome.go index 52dd5e6adb4..9e0f1bab689 100644 --- a/gnovm/pkg/gnoenv/gnohome.go +++ b/gnovm/pkg/gnoenv/gnohome.go @@ -29,7 +29,5 @@ func HomeDir() string { } gnoHome := filepath.Join(dir, "gno") - // XXX: added april 2023 as a transitory measure - remove after test4 - fixOldDefaultGnoHome(gnoHome) return gnoHome } diff --git a/gnovm/pkg/gnoenv/migration.go b/gnovm/pkg/gnoenv/migration.go deleted file mode 100644 index 5b1d1fd1fa0..00000000000 --- a/gnovm/pkg/gnoenv/migration.go +++ /dev/null @@ -1,28 +0,0 @@ -package gnoenv - -import ( - "log" - "os" - "path/filepath" -) - -// XXX: added april 2023 as a transitory measure - remove after test4 -func fixOldDefaultGnoHome(newDir string) { - dir, err := os.UserHomeDir() - if err != nil { - return - } - oldDir := filepath.Join(dir, ".gno") - s, err := os.Stat(oldDir) - if err != nil || !s.IsDir() { - return - } - if err = os.Rename(oldDir, newDir); err != nil { - if os.IsExist(err) { - log.Printf("WARNING: attempted moving old default GNO_HOME (%q) to new (%q) but failed because directory exists.", oldDir, newDir) - log.Printf("You may need to move files from the old directory manually, or set the env var GNO_HOME to %q to retain the old directory.", oldDir) - } else { - log.Printf("WARNING: attempted moving old default GNO_HOME (%q) to new (%q) but failed with error: %v", oldDir, newDir, err) - } - } -} diff --git a/gnovm/pkg/gnoenv/migration_test.go b/gnovm/pkg/gnoenv/migration_test.go deleted file mode 100644 index 86edd8502a1..00000000000 --- a/gnovm/pkg/gnoenv/migration_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package gnoenv - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestFixOldDefaultGnoHome(t *testing.T) { - tempHomeDir := t.TempDir() - t.Setenv("HOME", tempHomeDir) - - oldGnoHome := filepath.Join(tempHomeDir, ".gno") - newGnoHome := filepath.Join(tempHomeDir, "gno") - - // Create a dummy old GNO_HOME - os.Mkdir(oldGnoHome, 0o755) - - // Test migration - fixOldDefaultGnoHome(newGnoHome) - - _, errOld := os.Stat(oldGnoHome) - require.NotNil(t, errOld) - _, errNew := os.Stat(newGnoHome) - require.True(t, os.IsNotExist(errOld), "invalid errors", errOld) - require.NoError(t, errNew) -} From b655cd283d58f34e287d9c6bd6d76e1f338e84b3 Mon Sep 17 00:00:00 2001 From: rusttech Date: Sat, 19 Oct 2024 00:02:03 +0800 Subject: [PATCH 18/64] fix(cmd/aminoscan): set len=0 in a slice initialization (#2971)
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
The intention here should be to initialize a slice with a capacity of `len(args)` rather than initializing the length of this slice. The online demo: https://go.dev/play/p/q1BcVCmvidW --- tm2/pkg/amino/cmd/aminoscan/colors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm2/pkg/amino/cmd/aminoscan/colors.go b/tm2/pkg/amino/cmd/aminoscan/colors.go index 8dee9aed1f2..89f05a6a0cb 100644 --- a/tm2/pkg/amino/cmd/aminoscan/colors.go +++ b/tm2/pkg/amino/cmd/aminoscan/colors.go @@ -28,7 +28,7 @@ func treat(s string, color string) string { } func treatAll(color string, args ...interface{}) string { - parts := make([]string, len(args)) + parts := make([]string, 0, len(args)) for _, arg := range args { parts = append(parts, treat(fmt.Sprintf("%v", arg), color)) } From f6bd2d367d614798f0a412aa7bb209f8dc1c1d89 Mon Sep 17 00:00:00 2001 From: Alexis Colin Date: Sat, 19 Oct 2024 05:30:26 +0900 Subject: [PATCH 19/64] chore: add alexiscolin as gnoweb reviewer (#2967) As I'll be leading the collective efforts around gnoweb, it would be helpful if I could be automatically pinged for any PR review related to the `gnoweb` folder. This PR adds my GH handle as a codeowner for this directory. Thank you for your help! --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8566e861db9..bafaa70301b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -51,7 +51,7 @@ /gno.land/cmd/genesis/ @zivkovicmilos /gno.land/cmd/gnokey/ @jaekwon @moul @gfanton /gno.land/cmd/gnoland/ @zivkovicmilos @gnolang/devops -/gno.land/cmd/gnoweb/ @gfanton @thehowl +/gno.land/cmd/gnoweb/ @gfanton @thehowl @alexiscolin /gno.land/pkg/gnoclient/ @zivkovicmilos @leohhhn @gfanton /gno.land/pkg/gnoland/ @zivkovicmilos @gfanton /gno.land/pkg/keyscli/ @jaekwon @moul @gfanton From 93ece90f5ddb2eb44344db78d51479cad3bc10e5 Mon Sep 17 00:00:00 2001 From: Alexis Colin Date: Sun, 20 Oct 2024 22:06:45 +0900 Subject: [PATCH 20/64] feat(gnoweb): disable html in markdown (#2964) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In line with our vision for a HTML-free Gnoweb, this PR disables the rendering of HTML within Markdown content. It replaces all elements recognized as HTML tags (e.g., `
`, `
`, ``) with empty spaces before sending the content to the front-end. The parsing still happens via JavaScript, but now without any HTML tags. However, HTML tags like ``` `
lorem ipsum
` ``` can still appear within code blocks in Markdown, as usual, but won’t be parsed/read as actual HTML. Additionally, this feature is controlled by the `gnoweb` boolean flag `with-html`, which defaults to `false`. cc @gfanton > [!WARNING] > Enabling this feature will break the design of gno.land realms (and any other realms relying on HTML), since current layout elements like `columns`, `stacks`, or `jumbotrons`... are built with HTML. We will need to adopt the new design system expected with `gnoweb2.0` (or future `gnoweb1` improvements). ### BEFORE: ![127 0 0 1_8888_ (1)](https://github.com/user-attachments/assets/04328db4-7076-4690-9727-50c33f58954d) ### AFTER: ![127 0 0 1_8888_ (2)](https://github.com/user-attachments/assets/b8d9532c-45e6-4a78-b166-2f6d0176bd10) --- ### BEFORE: ![127 0 0 1_8888_r_gnoland_pages](https://github.com/user-attachments/assets/445cbb3f-565b-42af-b794-14f9c682d4ce) ### AFTER: ![127 0 0 1_8888_r_gnoland_pages (1)](https://github.com/user-attachments/assets/ac7131f1-c2d4-42ea-a426-66244782e910) --------- Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- contribs/gnodev/go.mod | 2 +- gno.land/cmd/gnoweb/main.go | 1 + gno.land/pkg/gnoweb/gnoweb.go | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/contribs/gnodev/go.mod b/contribs/gnodev/go.mod index f4859889a16..c419f968d4a 100644 --- a/contribs/gnodev/go.mod +++ b/contribs/gnodev/go.mod @@ -1,6 +1,6 @@ module github.com/gnolang/gno/contribs/gnodev -go 1.22 +go 1.22.0 replace github.com/gnolang/gno => ../.. diff --git a/gno.land/cmd/gnoweb/main.go b/gno.land/cmd/gnoweb/main.go index 547134548ff..5cec7257ebe 100644 --- a/gno.land/cmd/gnoweb/main.go +++ b/gno.land/cmd/gnoweb/main.go @@ -37,6 +37,7 @@ func runMain(args []string) error { fs.StringVar(&cfg.HelpRemote, "help-remote", cfg.HelpRemote, "help page's remote addr") fs.BoolVar(&cfg.WithAnalytics, "with-analytics", cfg.WithAnalytics, "enable privacy-first analytics") fs.StringVar(&bindAddress, "bind", "127.0.0.1:8888", "server listening address") + fs.BoolVar(&cfg.WithHTML, "with-html", cfg.WithHTML, "Enable HTML parsing in markdown rendering") if err := fs.Parse(args); err != nil { return err diff --git a/gno.land/pkg/gnoweb/gnoweb.go b/gno.land/pkg/gnoweb/gnoweb.go index 3e6249cf126..c0bc24ce216 100644 --- a/gno.land/pkg/gnoweb/gnoweb.go +++ b/gno.land/pkg/gnoweb/gnoweb.go @@ -13,6 +13,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "runtime" "strings" "time" @@ -45,6 +46,7 @@ type Config struct { HelpChainID string HelpRemote string WithAnalytics bool + WithHTML bool } func NewDefaultConfig() Config { @@ -56,6 +58,7 @@ func NewDefaultConfig() Config { HelpChainID: "dev", HelpRemote: "127.0.0.1:26657", WithAnalytics: false, + WithHTML: false, } } @@ -109,6 +112,34 @@ func MakeApp(logger *slog.Logger, cfg Config) gotuna.App { return app } +var ( + inlineCodePattern = regexp.MustCompile("`[^`]*`") + htmlTagPattern = regexp.MustCompile(`<\/?\w+[^>]*?>`) +) + +func sanitizeContent(cfg *Config, content string) string { + if cfg.WithHTML { + return content + } + + placeholders := map[string]string{} + contentWithPlaceholders := inlineCodePattern.ReplaceAllStringFunc(content, func(match string) string { + placeholder := fmt.Sprintf("__GNOMDCODE_%d__", len(placeholders)) + placeholders[placeholder] = match + return placeholder + }) + + sanitizedContent := htmlTagPattern.ReplaceAllString(contentWithPlaceholders, "") + + if len(placeholders) > 0 { + for placeholder, code := range placeholders { + sanitizedContent = strings.ReplaceAll(sanitizedContent, placeholder, code) + } + } + + return sanitizedContent +} + // handlerRealmAlias is used to render official pages from realms. // url is intended to be shorter. // UX is intended to be more minimalistic. @@ -151,7 +182,7 @@ func handlerRealmAlias(logger *slog.Logger, app gotuna.App, cfg *Config, rlmpath tmpl.Set("RealmPath", rlmpath) tmpl.Set("Query", querystr) tmpl.Set("PathLinks", pathLinks) - tmpl.Set("Contents", string(res.Data)) + tmpl.Set("Contents", sanitizeContent(cfg, string(res.Data))) tmpl.Set("Config", cfg) tmpl.Set("IsAlias", true) tmpl.Render(w, r, "realm_render.html", "funcs.html") @@ -339,7 +370,7 @@ func handleRealmRender(logger *slog.Logger, app gotuna.App, cfg *Config, w http. tmpl.Set("RealmPath", rlmpath) tmpl.Set("Query", querystr) tmpl.Set("PathLinks", pathLinks) - tmpl.Set("Contents", string(res.Data)) + tmpl.Set("Contents", sanitizeContent(cfg, string(res.Data))) tmpl.Set("Config", cfg) tmpl.Set("HasReadme", hasReadme) tmpl.Render(w, r, "realm_render.html", "funcs.html") From 24f0a0d2b58152e80f970b4148199bf7f7e9e540 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:41:14 -0400 Subject: [PATCH 21/64] chore: remove unused flag (#2990) Signed-off-by: moul <94029+moul@users.noreply.github.com> --- gno.land/cmd/gnoland/start.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/gno.land/cmd/gnoland/start.go b/gno.land/cmd/gnoland/start.go index 21f0cb4b1a6..d871cb65aa1 100644 --- a/gno.land/cmd/gnoland/start.go +++ b/gno.land/cmd/gnoland/start.go @@ -51,7 +51,6 @@ type startCfg struct { genesisFile string chainID string dataDir string - genesisMaxVMCycles int64 config string lazyInit bool @@ -137,13 +136,6 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) { "replacement for '%%REMOTE%%' in genesis", ) - fs.Int64Var( - &c.genesisMaxVMCycles, - "genesis-max-vm-cycles", - 100_000_000, - "set maximum allowed vm cycles per operation. Zero means no limit.", - ) - fs.StringVar( &c.config, flagConfigFlag, From 6fafe0eb33849f895f58477a093af94642068ac4 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:07:12 -0400 Subject: [PATCH 22/64] chore(cmd/gnoland): disable --flag-config-path (#2991) Not sure about this one. Is anyone using it? Signed-off-by: moul <94029+moul@users.noreply.github.com> Co-authored-by: Morgan --- gno.land/cmd/gnoland/root.go | 10 +--------- gno.land/cmd/gnoland/start.go | 8 -------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/gno.land/cmd/gnoland/root.go b/gno.land/cmd/gnoland/root.go index 8df716b1fed..b40a1160b0b 100644 --- a/gno.land/cmd/gnoland/root.go +++ b/gno.land/cmd/gnoland/root.go @@ -5,12 +5,8 @@ import ( "os" "github.com/gnolang/gno/tm2/pkg/commands" - "github.com/peterbourgon/ff/v3" - "github.com/peterbourgon/ff/v3/fftoml" ) -const flagConfigFlag = "flag-config-path" - func main() { cmd := newRootCmd(commands.NewDefaultIO()) @@ -21,11 +17,7 @@ func newRootCmd(io commands.IO) *commands.Command { cmd := commands.NewCommand( commands.Metadata{ ShortUsage: " [flags] [...]", - ShortHelp: "starts the gnoland blockchain node", - Options: []ff.Option{ - ff.WithConfigFileFlag(flagConfigFlag), - ff.WithConfigFileParser(fftoml.Parser), - }, + ShortHelp: "manages the gnoland blockchain node", }, commands.NewEmptyConfig(), commands.HelpExec, diff --git a/gno.land/cmd/gnoland/start.go b/gno.land/cmd/gnoland/start.go index d871cb65aa1..8d1ee81295f 100644 --- a/gno.land/cmd/gnoland/start.go +++ b/gno.land/cmd/gnoland/start.go @@ -51,7 +51,6 @@ type startCfg struct { genesisFile string chainID string dataDir string - config string lazyInit bool logLevel string @@ -136,13 +135,6 @@ func (c *startCfg) RegisterFlags(fs *flag.FlagSet) { "replacement for '%%REMOTE%%' in genesis", ) - fs.StringVar( - &c.config, - flagConfigFlag, - "", - "the flag config file (optional)", - ) - fs.StringVar( &c.logLevel, "log-level", From 464c7f114bf22d2b6b3632b3140f7554f34d4427 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Mon, 21 Oct 2024 17:07:38 +0200 Subject: [PATCH 23/64] feat(cmd/gno): lint all files in folder before panicking (#2202) This Pull request intents to follow up on #2011. As said on that Pull request, currently we show all lint errors on the first analyzed file. If in a folder we have `a.gno` & `b.gno` both with lint errors. `gno lint | run | test` will only find the errors related to one of those files. **This PR aims to show all the lint errors present on the current folder**. Changes: for lint & test cmd: - we modified ParseMemPackage function on gnovm/pkg/gnoland/nodes.go. Before this function returned as soon as an error was found while Parsing the gno file. So we introduced an error slice to keep track of all Parse errors. After parsing all the files we panic with the list of errors only if this list is not empty. - we did the same on parseMemPackageTests function - create a function printRuntimeError that handles the print of the errors inside `catchRuntimeError` function. We did this change in order to be able to recursively call the funtion and handle the case of an []error type composed of scanner.ErrorList errors. ### Results * running on gnovm/tests/integ/several-files-multiple/errors LINT (before): ```sh several-files-multiple-errors % gno lint . file2.gno:3: expected 'IDENT', found '{' (code=2). file2.gno:5: expected type, found '}' (code=2). ``` LINT (after): ```sh gno lint . file2.gno:3: expected 'IDENT', found '{' (code=2). file2.gno:5: expected type, found '}' (code=2). main.gno:5: expected ';', found example (code=2). main.gno:6: expected '}', found 'EOF' (code=2). exit status 1 ```
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- gnovm/cmd/gno/lint.go | 17 ++++++++++++----- gnovm/cmd/gno/lint_test.go | 4 ++++ gnovm/cmd/gno/run_test.go | 5 +++++ gnovm/cmd/gno/test.go | 7 ++++++- gnovm/pkg/gnolang/nodes.go | 8 +++++++- .../several-files-multiple-errors/file2.gno | 5 +++++ .../integ/several-files-multiple-errors/gno.mod | 1 + .../several-files-multiple-errors/main.gno | 6 ++++++ 8 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 gnovm/tests/integ/several-files-multiple-errors/file2.gno create mode 100644 gnovm/tests/integ/several-files-multiple-errors/gno.mod create mode 100644 gnovm/tests/integ/several-files-multiple-errors/main.gno diff --git a/gnovm/cmd/gno/lint.go b/gnovm/cmd/gno/lint.go index 6c497c7e2c0..c6008117f13 100644 --- a/gnovm/cmd/gno/lint.go +++ b/gnovm/cmd/gno/lint.go @@ -17,6 +17,7 @@ import ( "github.com/gnolang/gno/gnovm/tests" "github.com/gnolang/gno/tm2/pkg/commands" osm "github.com/gnolang/gno/tm2/pkg/os" + "go.uber.org/multierr" ) type lintCfg struct { @@ -174,12 +175,18 @@ func catchRuntimeError(pkgPath string, stderr io.WriteCloser, action func()) (ha case *gno.PreprocessError: err := verr.Unwrap() fmt.Fprint(stderr, issueFromError(pkgPath, err).String()+"\n") - case scanner.ErrorList: - for _, err := range verr { - fmt.Fprint(stderr, issueFromError(pkgPath, err).String()+"\n") - } case error: - fmt.Fprint(stderr, issueFromError(pkgPath, verr).String()+"\n") + errors := multierr.Errors(verr) + for _, err := range errors { + errList, ok := err.(scanner.ErrorList) + if ok { + for _, errorInList := range errList { + fmt.Fprint(stderr, issueFromError(pkgPath, errorInList).String()+"\n") + } + } else { + fmt.Fprint(stderr, issueFromError(pkgPath, err).String()+"\n") + } + } case string: fmt.Fprint(stderr, issueFromError(pkgPath, errors.New(verr)).String()+"\n") default: diff --git a/gnovm/cmd/gno/lint_test.go b/gnovm/cmd/gno/lint_test.go index a5c0319cd00..20d21c05d05 100644 --- a/gnovm/cmd/gno/lint_test.go +++ b/gnovm/cmd/gno/lint_test.go @@ -23,6 +23,10 @@ func TestLintApp(t *testing.T) { args: []string{"lint", "../../tests/integ/several-lint-errors/main.gno"}, stderrShouldContain: "../../tests/integ/several-lint-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-lint-errors/main.gno:6", errShouldBe: "exit code: 1", + }, { + args: []string{"lint", "../../tests/integ/several-files-multiple-errors/main.gno"}, + stderrShouldContain: "../../tests/integ/several-files-multiple-errors/file2.gno:3: expected 'IDENT', found '{' (code=2).\n../../tests/integ/several-files-multiple-errors/file2.gno:5: expected type, found '}' (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:6: expected '}', found 'EOF' (code=2).\n", + errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/run_main/"}, stderrShouldContain: "./../../tests/integ/run_main: missing 'gno.mod' file (code=1).", diff --git a/gnovm/cmd/gno/run_test.go b/gnovm/cmd/gno/run_test.go index 975868b7daf..e5aa1bd6279 100644 --- a/gnovm/cmd/gno/run_test.go +++ b/gnovm/cmd/gno/run_test.go @@ -83,6 +83,11 @@ func TestRunApp(t *testing.T) { args: []string{"run", "-expr", "Context()", "../../tests/integ/context/context.gno"}, stdoutShouldContain: "Context worked", }, + { + args: []string{"run", "../../tests/integ/several-files-multiple-errors/"}, + stderrShouldContain: "../../tests/integ/several-files-multiple-errors/file2.gno:3: expected 'IDENT', found '{' (code=2).\n../../tests/integ/several-files-multiple-errors/file2.gno:5: expected type, found '}' (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:6: expected '}', found 'EOF' (code=2).", + errShouldBe: "exit code: 1", + }, // TODO: a test file // TODO: args // TODO: nativeLibs VS stdlibs diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index 5884463a552..af7fa28a14d 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -577,6 +577,7 @@ func loadTestFuncs(pkgName string, t *testFuncs, tfiles *gno.FileSet) *testFuncs func parseMemPackageTests(memPkg *std.MemPackage) (tset, itset *gno.FileSet) { tset = &gno.FileSet{} itset = &gno.FileSet{} + var errs error for _, mfile := range memPkg.Files { if !strings.HasSuffix(mfile.Name, ".gno") { continue // skip this file. @@ -586,7 +587,8 @@ func parseMemPackageTests(memPkg *std.MemPackage) (tset, itset *gno.FileSet) { } n, err := gno.ParseFile(mfile.Name, mfile.Body) if err != nil { - panic(err) + errs = multierr.Append(errs, err) + continue } if n == nil { panic("should not happen") @@ -606,6 +608,9 @@ func parseMemPackageTests(memPkg *std.MemPackage) (tset, itset *gno.FileSet) { memPkg.Name, memPkg.Name, n.PkgName, mfile)) } } + if errs != nil { + panic(errs) + } return tset, itset } diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 5f5e8bd30b9..f1bd78ee646 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -14,6 +14,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/std" + "go.uber.org/multierr" ) // ---------------------------------------- @@ -1189,6 +1190,7 @@ func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { // or [ParseFile] returns an error, ParseMemPackage panics. func ParseMemPackage(memPkg *std.MemPackage) (fset *FileSet) { fset = &FileSet{} + var errs error for _, mfile := range memPkg.Files { if !strings.HasSuffix(mfile.Name, ".gno") || endsWith(mfile.Name, []string{"_test.gno", "_filetest.gno"}) { @@ -1196,7 +1198,8 @@ func ParseMemPackage(memPkg *std.MemPackage) (fset *FileSet) { } n, err := ParseFile(mfile.Name, mfile.Body) if err != nil { - panic(err) + errs = multierr.Append(errs, err) + continue } if memPkg.Name != string(n.PkgName) { panic(fmt.Sprintf( @@ -1206,6 +1209,9 @@ func ParseMemPackage(memPkg *std.MemPackage) (fset *FileSet) { // add package file. fset.AddFiles(n) } + if errs != nil { + panic(errs) + } return fset } diff --git a/gnovm/tests/integ/several-files-multiple-errors/file2.gno b/gnovm/tests/integ/several-files-multiple-errors/file2.gno new file mode 100644 index 00000000000..39ec59973ef --- /dev/null +++ b/gnovm/tests/integ/several-files-multiple-errors/file2.gno @@ -0,0 +1,5 @@ +package main + +type{ + +} \ No newline at end of file diff --git a/gnovm/tests/integ/several-files-multiple-errors/gno.mod b/gnovm/tests/integ/several-files-multiple-errors/gno.mod new file mode 100644 index 00000000000..88485411822 --- /dev/null +++ b/gnovm/tests/integ/several-files-multiple-errors/gno.mod @@ -0,0 +1 @@ +module gno.land/tests/severalerrors \ No newline at end of file diff --git a/gnovm/tests/integ/several-files-multiple-errors/main.gno b/gnovm/tests/integ/several-files-multiple-errors/main.gno new file mode 100644 index 00000000000..f29aa7ecd33 --- /dev/null +++ b/gnovm/tests/integ/several-files-multiple-errors/main.gno @@ -0,0 +1,6 @@ +package main + +func main() { + for { + _ example +} \ No newline at end of file From a5c1d186216a193e9b013226820eda02a93e22a1 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Mon, 21 Oct 2024 17:10:55 +0200 Subject: [PATCH 24/64] fix(tm2): avoid mutex copy in marshal and unmarshal methods (#2981) Avoid copying of Mutex at several places. Add missing lock / unlock calls. Improve test coverage for protobuf timestamp and duration. `go vet` doesn't complain anymore on Mutex copy. Addresses #2954.
Contributors' checklist... - [*] Added new tests, or not needed, or not feasible - [*] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [*] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [*] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- tm2/pkg/amino/amino.go | 2 +- tm2/pkg/amino/json_test.go | 29 ++++++++++++++++++++++++++++- tm2/pkg/amino/wellknown.go | 23 +++++++++++++++-------- tm2/pkg/bitarray/bit_array.go | 12 +++++++++++- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/tm2/pkg/amino/amino.go b/tm2/pkg/amino/amino.go index ecff955a582..e402c74f4fd 100644 --- a/tm2/pkg/amino/amino.go +++ b/tm2/pkg/amino/amino.go @@ -760,7 +760,7 @@ func (cdc *Codec) MarshalJSON(o interface{}) ([]byte, error) { cdc.doAutoseal() rv := reflect.ValueOf(o) - if rv.Kind() == reflect.Invalid { + if !rv.IsValid() { return []byte("null"), nil } rt := rv.Type() diff --git a/tm2/pkg/amino/json_test.go b/tm2/pkg/amino/json_test.go index e3f7d413fcb..9b5cd9cff09 100644 --- a/tm2/pkg/amino/json_test.go +++ b/tm2/pkg/amino/json_test.go @@ -12,8 +12,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" - amino "github.com/gnolang/gno/tm2/pkg/amino" + "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/amino/pkg" ) @@ -158,6 +160,31 @@ func TestMarshalJSONTime(t *testing.T) { assert.Equal(t, s, s2) } +func TestMarshalJSONPBTime(t *testing.T) { + t.Parallel() + + cdc := amino.NewCodec() + registerTransports(cdc) + + type SimpleStruct struct { + Timestamp *timestamppb.Timestamp + Duration *durationpb.Duration + } + + s := SimpleStruct{ + Timestamp: ×tamppb.Timestamp{Seconds: 1296012345, Nanos: 940483}, + Duration: &durationpb.Duration{Seconds: 100}, + } + + b, err := cdc.MarshalJSON(s) + assert.Nil(t, err) + + var s2 SimpleStruct + err = cdc.UnmarshalJSON(b, &s2) + assert.Nil(t, err) + assert.Equal(t, s, s2) +} + type fp struct { Name string Version int diff --git a/tm2/pkg/amino/wellknown.go b/tm2/pkg/amino/wellknown.go index 9dbafcbecec..7720c2894d9 100644 --- a/tm2/pkg/amino/wellknown.go +++ b/tm2/pkg/amino/wellknown.go @@ -237,16 +237,21 @@ func encodeReflectJSONWellKnown(w io.Writer, info *TypeInfo, rv reflect.Value, f } return true, nil // Google "well known" types. + // The protobuf Timestamp and Duration values contain a Mutex, and therefore must not be copied. + // The corresponding reflect value may not be addressable, we can not safely get their pointer. + // So we just extract the `Seconds` and `Nanos` fields from the reflect value, without copying + // the whole struct, and encode them as their coresponding time.Time or time.Duration value. case gTimestampType: - t := rv.Interface().(timestamppb.Timestamp) - err = EncodeJSONPBTimestamp(w, t) + t := time.Unix(rv.Interface().(timestamppb.Timestamp).Seconds, int64(rv.Interface().(timestamppb.Timestamp).Nanos)) + err = EncodeJSONTime(w, t) if err != nil { return false, err } return true, nil case gDurationType: - d := rv.Interface().(durationpb.Duration) - err = EncodeJSONPBDuration(w, d) + d := time.Duration(rv.Interface().(durationpb.Duration).Seconds) * time.Second + d += time.Duration(rv.Interface().(durationpb.Duration).Nanos) + err = EncodeJSONDuration(w, d) if err != nil { return false, err } @@ -300,7 +305,8 @@ func decodeReflectJSONWellKnown(bz []byte, info *TypeInfo, rv reflect.Value, fop if err != nil { return false, err } - rv.Set(reflect.ValueOf(t)) + rv.FieldByName("Seconds").Set(reflect.ValueOf(t.Seconds)) + rv.FieldByName("Nanos").Set(reflect.ValueOf(t.Nanos)) return true, nil case gDurationType: var d durationpb.Duration @@ -308,7 +314,8 @@ func decodeReflectJSONWellKnown(bz []byte, info *TypeInfo, rv reflect.Value, fop if err != nil { return false, err } - rv.Set(reflect.ValueOf(d)) + rv.FieldByName("Seconds").Set(reflect.ValueOf(d.Seconds)) + rv.FieldByName("Nanos").Set(reflect.ValueOf(d.Nanos)) return true, nil // TODO: port each below to above without proto dependency // for unmarshaling code, to minimize dependencies. @@ -426,7 +433,7 @@ func EncodeJSONTime(w io.Writer, t time.Time) (err error) { return EncodeJSONTimeValue(w, t.Unix(), int32(t.Nanosecond())) } -func EncodeJSONPBTimestamp(w io.Writer, t timestamppb.Timestamp) (err error) { +func EncodeJSONPBTimestamp(w io.Writer, t *timestamppb.Timestamp) (err error) { return EncodeJSONTimeValue(w, t.GetSeconds(), t.GetNanos()) } @@ -456,7 +463,7 @@ func EncodeJSONDuration(w io.Writer, d time.Duration) (err error) { return EncodeJSONDurationValue(w, int64(d)/1e9, int32(int64(d)%1e9)) } -func EncodeJSONPBDuration(w io.Writer, d durationpb.Duration) (err error) { +func EncodeJSONPBDuration(w io.Writer, d *durationpb.Duration) (err error) { return EncodeJSONDurationValue(w, d.GetSeconds(), d.GetNanos()) } diff --git a/tm2/pkg/bitarray/bit_array.go b/tm2/pkg/bitarray/bit_array.go index 2f7b184b938..a48c71a5650 100644 --- a/tm2/pkg/bitarray/bit_array.go +++ b/tm2/pkg/bitarray/bit_array.go @@ -394,8 +394,12 @@ func (bA *BitArray) UnmarshalJSON(bz []byte) error { if b == "null" { // This is required e.g. for encoding/json when decoding // into a pointer with pre-allocated BitArray. + bA.mtx.Lock() + defer bA.mtx.Unlock() + bA.Bits = 0 bA.Elems = nil + return nil } @@ -414,6 +418,12 @@ func (bA *BitArray) UnmarshalJSON(bz []byte) error { bA2.SetIndex(i, true) } } - *bA = *bA2 //nolint:govet + + bA.mtx.Lock() + defer bA.mtx.Unlock() + + bA.Bits = bA2.Bits + bA.Elems = bA2.Elems + return nil } From 13dfd218a040afe1675a5f7e8942e3042ace9d3e Mon Sep 17 00:00:00 2001 From: Leon Hudak <33522493+leohhhn@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:12:29 +0200 Subject: [PATCH 25/64] chore(pages): update bounty Terms & Conditions link (#2982) ## Description By internal request.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests
--- examples/gno.land/r/gnoland/pages/page_contribute.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/gnoland/pages/page_contribute.gno b/examples/gno.land/r/gnoland/pages/page_contribute.gno index a4bdfabb6ef..0855dc327cd 100644 --- a/examples/gno.land/r/gnoland/pages/page_contribute.gno +++ b/examples/gno.land/r/gnoland/pages/page_contribute.gno @@ -45,7 +45,7 @@ Don't fear your work being "stolen": if a submission is the result of multiple p - 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). +Participants in the gno.land Bounty Program must meet the legal Terms and Conditions referenced [here](https://docs.google.com/document/d/e/2PACX-1vSUF-JwIXGscrNsc5QBD7Pa6i83mXUGogAEIf1wkeb_w42UgL3Lj6jFKMlNTdwEMUnhsLkjRlhe25K4/pub). ### Bounty sizes From 88a0c4e41d6ecc011261b94a8293dfdb9a52072e Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:14:57 +0200 Subject: [PATCH 26/64] fix(gonative): add constant information when we define a go native value (#2848) First part of the fix: https://github.com/gnolang/gno/issues/2836 The second part is addressed here: https://github.com/gnolang/gno/pull/2731 --- gnovm/pkg/gnolang/gonative.go | 15 ++++-- gnovm/pkg/gnolang/preprocess.go | 4 ++ gnovm/pkg/gnolang/preprocess_test.go | 8 ++-- gnovm/tests/files/assign29_native.gno | 14 ++++++ gnovm/tests/imports.go | 67 +++++++++++++-------------- 5 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 gnovm/tests/files/assign29_native.gno diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 0676854aa39..fe92f5bcd23 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -1258,16 +1258,25 @@ func (x *PackageNode) DefineGoNativeType(rt reflect.Type) { x.Define(Name(name), asValue(nt)) } -func (x *PackageNode) DefineGoNativeValue(n Name, nv interface{}) { +func (x *PackageNode) DefineGoNativeValue(name Name, nv interface{}) { + x.defineGoNativeValue(false, name, nv) +} + +func (x *PackageNode) DefineGoNativeConstValue(name Name, nv interface{}) { + x.defineGoNativeValue(true, name, nv) +} + +func (x *PackageNode) defineGoNativeValue(isConst bool, n Name, nv interface{}) { if debug { - debug.Printf("*PackageNode.DefineGoNativeValue(%s)\n", reflect.ValueOf(nv).String()) + debug.Printf("*PackageNode.defineGoNativeValue(%s)\n", reflect.ValueOf(nv).String()) } rv := reflect.ValueOf(nv) // rv is not settable, so create something that is. rt := rv.Type() rv2 := reflect.New(rt).Elem() rv2.Set(rv) - x.Define(n, go2GnoValue(nilAllocator, rv2)) + tv := go2GnoValue(nilAllocator, rv2) + x.Define2(isConst, n, tv.T, tv) } // ---------------------------------------- diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 61096626f28..757cbbae317 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2093,6 +2093,10 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // General case: a, b = x, y. for i, lx := range n.Lhs { lt := evalStaticTypeOf(store, last, lx) + if nt, ok := lt.(*NativeType); ok && nt.Kind() == FuncKind { + panic(fmt.Sprintf("cannot assign to %s (neither addressable nor a map index expression)", lx)) + } + // if lt is interface, nothing will happen checkOrConvertType(store, last, &n.Rhs[i], lt, true) } diff --git a/gnovm/pkg/gnolang/preprocess_test.go b/gnovm/pkg/gnolang/preprocess_test.go index 73e1318b062..53ad97dd972 100644 --- a/gnovm/pkg/gnolang/preprocess_test.go +++ b/gnovm/pkg/gnolang/preprocess_test.go @@ -11,8 +11,8 @@ import ( func TestPreprocess_BinaryExpressionOneNative(t *testing.T) { pn := NewPackageNode("time", "time", nil) - pn.DefineGoNativeValue("Millisecond", time.Millisecond) - pn.DefineGoNativeValue("Second", time.Second) + pn.DefineGoNativeConstValue("Millisecond", time.Millisecond) + pn.DefineGoNativeConstValue("Second", time.Second) pn.DefineGoNativeType(reflect.TypeOf(time.Duration(0))) pv := pn.NewPackage() store := gonativeTestStore(pn, pv) @@ -37,8 +37,8 @@ func main() { func TestPreprocess_BinaryExpressionBothNative(t *testing.T) { pn := NewPackageNode("time", "time", nil) - pn.DefineGoNativeValue("March", time.March) - pn.DefineGoNativeValue("Wednesday", time.Wednesday) + pn.DefineGoNativeConstValue("March", time.March) + pn.DefineGoNativeConstValue("Wednesday", time.Wednesday) pn.DefineGoNativeType(reflect.TypeOf(time.Month(0))) pn.DefineGoNativeType(reflect.TypeOf(time.Weekday(0))) pv := pn.NewPackage() diff --git a/gnovm/tests/files/assign29_native.gno b/gnovm/tests/files/assign29_native.gno new file mode 100644 index 00000000000..a404f703fc1 --- /dev/null +++ b/gnovm/tests/files/assign29_native.gno @@ -0,0 +1,14 @@ +package main + +import ( + "time" +) + +func main() { + time.Now = func() time.Time { + return time.Time{} + } +} + +// Error: +// main/files/assign29_native.gno:8:2: cannot assign to time.Now (neither addressable nor a map index expression) diff --git a/gnovm/tests/imports.go b/gnovm/tests/imports.go index b8532253ce3..66398ba5f50 100644 --- a/gnovm/tests/imports.go +++ b/gnovm/tests/imports.go @@ -222,23 +222,23 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri return pkg, pkg.NewPackage() case "time": pkg := gno.NewPackageNode("time", pkgPath, nil) - pkg.DefineGoNativeValue("Millisecond", time.Millisecond) - pkg.DefineGoNativeValue("Second", time.Second) - pkg.DefineGoNativeValue("Minute", time.Minute) - pkg.DefineGoNativeValue("Hour", time.Hour) - pkg.DefineGoNativeValue("Date", time.Date) - pkg.DefineGoNativeValue("Now", func() time.Time { return time.Unix(0, 0).UTC() }) // deterministic - pkg.DefineGoNativeValue("January", time.January) - pkg.DefineGoNativeValue("February", time.February) - pkg.DefineGoNativeValue("March", time.March) - pkg.DefineGoNativeValue("April", time.April) - pkg.DefineGoNativeValue("May", time.May) - pkg.DefineGoNativeValue("June", time.June) - pkg.DefineGoNativeValue("July", time.July) - pkg.DefineGoNativeValue("August", time.August) - pkg.DefineGoNativeValue("September", time.September) - pkg.DefineGoNativeValue("November", time.November) - pkg.DefineGoNativeValue("December", time.December) + pkg.DefineGoNativeConstValue("Millisecond", time.Millisecond) + pkg.DefineGoNativeConstValue("Second", time.Second) + pkg.DefineGoNativeConstValue("Minute", time.Minute) + pkg.DefineGoNativeConstValue("Hour", time.Hour) + pkg.DefineGoNativeConstValue("Date", time.Date) + pkg.DefineGoNativeConstValue("Now", func() time.Time { return time.Unix(0, 0).UTC() }) // deterministic + pkg.DefineGoNativeConstValue("January", time.January) + pkg.DefineGoNativeConstValue("February", time.February) + pkg.DefineGoNativeConstValue("March", time.March) + pkg.DefineGoNativeConstValue("April", time.April) + pkg.DefineGoNativeConstValue("May", time.May) + pkg.DefineGoNativeConstValue("June", time.June) + pkg.DefineGoNativeConstValue("July", time.July) + pkg.DefineGoNativeConstValue("August", time.August) + pkg.DefineGoNativeConstValue("September", time.September) + pkg.DefineGoNativeConstValue("November", time.November) + pkg.DefineGoNativeConstValue("December", time.December) pkg.DefineGoNativeValue("UTC", time.UTC) pkg.DefineGoNativeValue("Unix", time.Unix) pkg.DefineGoNativeType(reflect.TypeOf(time.Time{})) @@ -272,21 +272,20 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg := gno.NewPackageNode("math", pkgPath, nil) pkg.DefineGoNativeValue("Abs", math.Abs) pkg.DefineGoNativeValue("Cos", math.Cos) - pkg.DefineGoNativeValue("Pi", math.Pi) + pkg.DefineGoNativeConstValue("Pi", math.Pi) pkg.DefineGoNativeValue("Float64bits", math.Float64bits) - pkg.DefineGoNativeValue("Pi", math.Pi) - pkg.DefineGoNativeValue("MaxFloat32", math.MaxFloat32) - pkg.DefineGoNativeValue("MaxFloat64", math.MaxFloat64) - pkg.DefineGoNativeValue("MaxUint32", uint32(math.MaxUint32)) - pkg.DefineGoNativeValue("MaxUint64", uint64(math.MaxUint64)) - pkg.DefineGoNativeValue("MinInt8", math.MinInt8) - pkg.DefineGoNativeValue("MinInt16", math.MinInt16) - pkg.DefineGoNativeValue("MinInt32", math.MinInt32) - pkg.DefineGoNativeValue("MinInt64", int64(math.MinInt64)) - pkg.DefineGoNativeValue("MaxInt8", math.MaxInt8) - pkg.DefineGoNativeValue("MaxInt16", math.MaxInt16) - pkg.DefineGoNativeValue("MaxInt32", math.MaxInt32) - pkg.DefineGoNativeValue("MaxInt64", int64(math.MaxInt64)) + pkg.DefineGoNativeConstValue("MaxFloat32", math.MaxFloat32) + pkg.DefineGoNativeConstValue("MaxFloat64", math.MaxFloat64) + pkg.DefineGoNativeConstValue("MaxUint32", uint32(math.MaxUint32)) + pkg.DefineGoNativeConstValue("MaxUint64", uint64(math.MaxUint64)) + pkg.DefineGoNativeConstValue("MinInt8", math.MinInt8) + pkg.DefineGoNativeConstValue("MinInt16", math.MinInt16) + pkg.DefineGoNativeConstValue("MinInt32", math.MinInt32) + pkg.DefineGoNativeConstValue("MinInt64", int64(math.MinInt64)) + pkg.DefineGoNativeConstValue("MaxInt8", math.MaxInt8) + pkg.DefineGoNativeConstValue("MaxInt16", math.MaxInt16) + pkg.DefineGoNativeConstValue("MaxInt32", math.MaxInt32) + pkg.DefineGoNativeConstValue("MaxInt64", int64(math.MaxInt64)) return pkg, pkg.NewPackage() case "math/rand": // XXX only expose for tests. @@ -321,13 +320,13 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri return pkg, pkg.NewPackage() case "compress/flate": pkg := gno.NewPackageNode("flate", pkgPath, nil) - pkg.DefineGoNativeValue("BestSpeed", flate.BestSpeed) + pkg.DefineGoNativeConstValue("BestSpeed", flate.BestSpeed) return pkg, pkg.NewPackage() case "compress/gzip": pkg := gno.NewPackageNode("gzip", pkgPath, nil) pkg.DefineGoNativeType(reflect.TypeOf(gzip.Writer{})) - pkg.DefineGoNativeValue("BestCompression", gzip.BestCompression) - pkg.DefineGoNativeValue("BestSpeed", gzip.BestSpeed) + pkg.DefineGoNativeConstValue("BestCompression", gzip.BestCompression) + pkg.DefineGoNativeConstValue("BestSpeed", gzip.BestSpeed) return pkg, pkg.NewPackage() case "context": pkg := gno.NewPackageNode("context", pkgPath, nil) From af169ffd233caabae746b18c9381c7ad695ebbed Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Mon, 21 Oct 2024 20:28:16 +0200 Subject: [PATCH 27/64] fix(ghverify): fix avl tree iteration in `Render` and `GetFeedDefinitions` (#2933) This pull request resolves a bug in the iteration logic of the `iterate` function from `gno.land/p/demo/avl` (avlTree) as used in two key areas: the `Render` function of `gno.land/r/gnoland/ghverify` and the `GetFeedDefinitions` function of `gno.land/p/demo/gnorkle/gnorkle`. ### Problem: In both instances, the `iterate` function was returning `true` after processing the first item, which prematurely halted the iteration. As a result, only the first item was processed, and all subsequent items were ignored. --- .../p/demo/gnorkle/gnorkle/instance.gno | 2 +- .../gno.land/r/gnoland/ghverify/contract.gno | 2 +- .../r/gnoland/ghverify/contract_test.gno | 33 +++++++++++-------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/examples/gno.land/p/demo/gnorkle/gnorkle/instance.gno b/examples/gno.land/p/demo/gnorkle/gnorkle/instance.gno index 22746d569a8..eea4782909e 100644 --- a/examples/gno.land/p/demo/gnorkle/gnorkle/instance.gno +++ b/examples/gno.land/p/demo/gnorkle/gnorkle/instance.gno @@ -227,7 +227,7 @@ func (i *Instance) GetFeedDefinitions(forAddress string) (string, error) { first = false buf.Write(taskBytes) - return true + return false }) if err != nil { diff --git a/examples/gno.land/r/gnoland/ghverify/contract.gno b/examples/gno.land/r/gnoland/ghverify/contract.gno index b40c9ef1448..4f2715b79e7 100644 --- a/examples/gno.land/r/gnoland/ghverify/contract.gno +++ b/examples/gno.land/r/gnoland/ghverify/contract.gno @@ -139,7 +139,7 @@ func Render(_ string) string { result += `"` + handle + `": "` + address.(string) + `"` appendComma = true - return true + return false }) return result + "}" diff --git a/examples/gno.land/r/gnoland/ghverify/contract_test.gno b/examples/gno.land/r/gnoland/ghverify/contract_test.gno index d9c399942ae..5c0be0afcb1 100644 --- a/examples/gno.land/r/gnoland/ghverify/contract_test.gno +++ b/examples/gno.land/r/gnoland/ghverify/contract_test.gno @@ -9,7 +9,8 @@ import ( func TestVerificationLifecycle(t *testing.T) { defaultAddress := std.GetOrigCaller() - userAddress := std.Address(testutils.TestAddress("user")) + user1Address := std.Address(testutils.TestAddress("user 1")) + user2Address := std.Address(testutils.TestAddress("user 2")) // Verify request returns no feeds. result := GnorkleEntrypoint("request") @@ -18,7 +19,7 @@ func TestVerificationLifecycle(t *testing.T) { } // Make a verification request with the created user. - std.TestSetOrigCaller(userAddress) + std.TestSetOrigCaller(user1Address) RequestVerification("deelawn") // A subsequent request from the same address should panic because there is @@ -42,26 +43,32 @@ func TestVerificationLifecycle(t *testing.T) { t.Fatalf("expected empty request result, got %s", result) } + // Make a verification request with the created user. + std.TestSetOrigCaller(user2Address) + RequestVerification("omarsy") + // Set the caller back to the whitelisted user and verify that the feed data // returned matches what should have been created by the `RequestVerification` // invocation. std.TestSetOrigCaller(defaultAddress) result = GnorkleEntrypoint("request") - expResult := `[{"id":"` + string(userAddress) + `","type":"0","value_type":"string","tasks":[{"gno_address":"` + - string(userAddress) + `","github_handle":"deelawn"}]}]` + expResult := `[{"id":"` + string(user1Address) + `","type":"0","value_type":"string","tasks":[{"gno_address":"` + + string(user1Address) + `","github_handle":"deelawn"}]},` + + `{"id":"` + string(user2Address) + `","type":"0","value_type":"string","tasks":[{"gno_address":"` + + string(user2Address) + `","github_handle":"omarsy"}]}]` if result != expResult { t.Fatalf("expected request result %s, got %s", expResult, result) } // Try to trigger feed ingestion from the non-authorized user. - std.TestSetOrigCaller(userAddress) + std.TestSetOrigCaller(user1Address) func() { defer func() { if r := recover(); r != nil { errMsg = r.(error).Error() } }() - GnorkleEntrypoint("ingest," + string(userAddress) + ",OK") + GnorkleEntrypoint("ingest," + string(user1Address) + ",OK") }() if errMsg != "caller not whitelisted" { t.Fatalf("expected caller not whitelisted, got %s", errMsg) @@ -69,15 +76,15 @@ func TestVerificationLifecycle(t *testing.T) { // Set the caller back to the whitelisted user and transfer contract ownership. std.TestSetOrigCaller(defaultAddress) - SetOwner(userAddress) + SetOwner(defaultAddress) // Now trigger the feed ingestion from the user and new owner and only whitelisted address. - std.TestSetOrigCaller(userAddress) - GnorkleEntrypoint("ingest," + string(userAddress) + ",OK") + GnorkleEntrypoint("ingest," + string(user1Address) + ",OK") + GnorkleEntrypoint("ingest," + string(user2Address) + ",OK") // Verify the ingestion autocommitted the value and triggered the post handler. data := Render("") - expResult = `{"deelawn": "` + string(userAddress) + `"}` + expResult = `{"deelawn": "` + string(user1Address) + `","omarsy": "` + string(user2Address) + `"}` if data != expResult { t.Fatalf("expected render data %s, got %s", expResult, data) } @@ -89,10 +96,10 @@ func TestVerificationLifecycle(t *testing.T) { } // Check that the accessor functions are working as expected. - if handle := GetHandleByAddress(string(userAddress)); handle != "deelawn" { + if handle := GetHandleByAddress(string(user1Address)); handle != "deelawn" { t.Fatalf("expected deelawn, got %s", handle) } - if address := GetAddressByHandle("deelawn"); address != string(userAddress) { - t.Fatalf("expected %s, got %s", string(userAddress), address) + if address := GetAddressByHandle("deelawn"); address != string(user1Address) { + t.Fatalf("expected %s, got %s", string(user1Address), address) } } From 8417ca436350d983d7310ea11bdd118ee15d15eb Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 21 Oct 2024 20:58:59 +0200 Subject: [PATCH 28/64] chore: remove misc/logos (#2965) Unmaintained, and we're going in another direction with gnobro anyway. --- .github/workflows/misc.yml | 1 - misc/logos/README.md | 11 - misc/logos/buffer.go | 355 ------------- misc/logos/cmd/logos.go | 171 ------ misc/logos/image.png | Bin 479803 -> 0 bytes misc/logos/misc.go | 155 ------ misc/logos/misc_test.go | 166 ------ misc/logos/stack.go | 160 ------ misc/logos/types.go | 1006 ------------------------------------ misc/logos/types_test.go | 47 -- misc/logos/unicode.go | 86 --- 11 files changed, 2158 deletions(-) delete mode 100644 misc/logos/README.md delete mode 100644 misc/logos/buffer.go delete mode 100644 misc/logos/cmd/logos.go delete mode 100644 misc/logos/image.png delete mode 100644 misc/logos/misc.go delete mode 100644 misc/logos/misc_test.go delete mode 100644 misc/logos/stack.go delete mode 100644 misc/logos/types.go delete mode 100644 misc/logos/types_test.go delete mode 100644 misc/logos/unicode.go diff --git a/.github/workflows/misc.yml b/.github/workflows/misc.yml index b824235ca2b..859e1429983 100644 --- a/.github/workflows/misc.yml +++ b/.github/workflows/misc.yml @@ -22,7 +22,6 @@ jobs: - genproto - genstd - goscan - - logos - loop name: Run Main uses: ./.github/workflows/main_template.yml diff --git a/misc/logos/README.md b/misc/logos/README.md deleted file mode 100644 index ba8ac8333a6..00000000000 --- a/misc/logos/README.md +++ /dev/null @@ -1,11 +0,0 @@ -## Logos Browser - -[Logos](/logos) is a Gno object browser. The modern browser as well as the -modern javascript ecosystem is from a security point of view, completely fucked. -The entire paradigm of continuously updating browsers with incrementally added -features is a security nightmare. - -The Logos browser is based on a new model that is vastly simpler than HTML. -The purpose of Logos is to become a fully expressive web API and implementation -standard that does most of what HTML and the World Wide Web originally intended -to do, but without becoming more complex than necessary. diff --git a/misc/logos/buffer.go b/misc/logos/buffer.go deleted file mode 100644 index 81e8d1abc75..00000000000 --- a/misc/logos/buffer.go +++ /dev/null @@ -1,355 +0,0 @@ -package logos - -import ( - "fmt" - "strings" - - "github.com/gdamore/tcell/v2" -) - -// ---------------------------------------- -// Buffer - -// A Buffer is a buffer area in which to draw. -type Buffer struct { - Size - Cells []Cell -} - -func NewBuffer(sz Size) *Buffer { - return &Buffer{ - Size: sz, - Cells: make([]Cell, sz.Width*sz.Height), - } -} - -func (bb *Buffer) Reset() { - sz := bb.Size - bb.Cells = make([]Cell, sz.Width*sz.Height) -} - -func (bb *Buffer) GetCell(x, y int) *Cell { - if bb.Width <= x { - panic(fmt.Sprintf( - "index x=%d out of bounds, width=%d", - x, bb.Width)) - } - if bb.Height <= y { - panic(fmt.Sprintf( - "index y=%d out of bounds, height=%d", - y, bb.Height)) - } - return &bb.Cells[y*bb.Width+x] -} - -func (bb *Buffer) Sprint() string { - lines := []string{} - for y := 0; y < bb.Height; y++ { - parts := []string{} - for x := 0; x < bb.Width; x++ { - cell := bb.GetCell(x, y) - parts = append(parts, cell.Character) - // NOTE: hacky way to debug. - if true { - attrs := cell.GetAttrs() - flags := attrs.GetAttrFlags() - parts = append(parts, - fmt.Sprintf("%X", flags)) - } - } - line := strings.Join(parts, "") - lines = append(lines, line) - } - return strings.Join(lines, "\n") -} - -func (bb *Buffer) DrawToScreen(s tcell.Screen) { - sw, sh := s.Size() - if bb.Size.Width != sw || bb.Size.Height != sh { - panic("buffer doesn't match screen size") - } - for y := 0; y < sh; y++ { - for x := 0; x < sw; x++ { - cell := bb.GetCell(x, y) - if x == 0 && y == 0 { - // NOTE: to thwart some inexplicable bugs. - s.SetContent(0, 0, tcell.RunePlus, nil, gDefaultSpaceTStyle) - } else { - mainc, combc, tstyle := cell.GetTCellContent() - s.SetContent(x, y, mainc, combc, tstyle) - } - } - } -} - -// ---------------------------------------- -// Cell - -// A terminal character cell. -type Cell struct { - Character string // 1 unicode character, or " ". - Width int - *Style - Attrs - Ref Elem // reference to element -} - -// NOTE: there is a difference in behavior -// from SetValue(...,c2) when c2 has -// attributes not present in c2.Ref, so the -// two are not equivalent. -func (cc *Cell) SetValueFromCell(c2 *Cell) { - cc.SetValue(c2.Character, c2.Width, c2.Style, c2.Ref) - cc.Character = c2.Character - cc.Width = c2.Width - if c2.Style != nil { - cc.Style = c2.Style - } - cc.Attrs.Merge(c2.GetAttrs()) - if c2.Ref != nil { - cc.Ref = c2.Ref - } -} - -func (cc *Cell) SetValue(chs string, w int, st *Style, el Elem) { - cc.Character = chs - cc.Width = w - if st != nil { - cc.Style = st - } - if el != nil { - cc.Attrs.Merge(el.GetAttrs()) - cc.Ref = el - } -} - -func (cc *Cell) Reset() { - *cc = Cell{} -} - -var gDefaultSpaceTStyle = tcell.StyleDefault. - Dim(true). - Background(tcell.ColorGray) - -// This is where a bit of dynamic logic is performed, -// namely where the attr is used to derive the final style. -func (cc *Cell) GetTCellContent() (mainc rune, combc []rune, tstyle tcell.Style) { - style := cc.Style - attrs := &cc.Attrs - if cc.Character == "" { - mainc = '?' // for debugging - if style == nil { - // special case - tstyle = gDefaultSpaceTStyle - } else { - tstyle = style.WithAttrs(attrs).GetTStyle() - } - } else { - rz := toRunes(cc.Character) - mainc = rz[0] - combc = rz[1:] - if style == nil { - tstyle = gDefaultStyle.WithAttrs(attrs).GetTStyle() - } else { - tstyle = style.WithAttrs(attrs).GetTStyle() - } - } - return -} - -// ---------------------------------------- -// View -// analogy: "Buffer:View :: array:slice". - -// Offset and Size must be within bounds of *Buffer. -type View struct { - Base *Buffer - Offset Coord // offset within Buffer - Bounds Size // total size of slice -} - -// offset elements must be 0 or positive. -func (bb *Buffer) NewView(offset Coord) View { - if !offset.IsNonNegative() { - panic("should not happen") - } - return View{ - Base: bb, - Offset: offset, - Bounds: bb.Size, - } -} - -func (bs View) NewView(offset Coord) View { - return View{ - Base: bs.Base, - Offset: bs.Offset.Add(offset), - Bounds: bs.Bounds.SubCoord(offset), - } -} - -func (bs View) GetCell(x, y int) *Cell { - if bs.Bounds.Width <= x { - panic("should not happen") - } - if bs.Bounds.Height <= y { - panic("should not happen") - } - return bs.Base.GetCell( - bs.Offset.X+x, - bs.Offset.Y+y, - ) -} - -// ---------------------------------------- -// BufferedView - -// A view onto an element. -// Somewhat like a slice onto an array -// (as a view is onto an elem), -// except cells are allocated here. -type BufferedElemView struct { - Coord - Size - *Style - Attrs // e.g. to focus on a scrollbar - Base Elem // the underlying elem - Offset Coord // within elem for pagination - *Buffer // view's internal draw screen -} - -// Returns a new *BufferedElemView that spans the whole elem. -// If size is zero, the elem is measured first to get the full -// buffer size. The result must still be rendered before drawing. The -// *BufferedElemView inherits the style and coordinates of the elem, and -// the elem's coord is set to zero. -func NewBufferedElemView(elem Elem, size Size) *BufferedElemView { - if size.IsZero() { - size = elem.Measure() - } - bpv := &BufferedElemView{ - Size: size, - Style: elem.GetStyle(), - Base: elem, - Offset: Coord{0, 0}, - // NOTE: be lazy, size may change. - // Buffer: NewBuffer(size), - } - bpv.SetCoord(elem.GetCoord()) - bpv.SetIsDirty(true) - elem.SetParent(bpv) - elem.SetCoord(Coord{}) // required for abs calc. - return bpv -} - -func (bpv *BufferedElemView) StringIndented(indent string) string { - return fmt.Sprintf("Buffered%v@%p\n%s %s", - bpv.Size, - bpv, - indent, - bpv.Base.StringIndented(indent+" ")) -} - -func (bpv *BufferedElemView) String() string { - return fmt.Sprintf("Buffered%v{%v}@%p", - bpv.Size, - bpv.Base, - bpv) -} - -// Pass on style to the base elem. -func (bpv *BufferedElemView) SetStyle(style *Style) { - bpv.Style = style - bpv.Base.SetStyle(style) - bpv.SetIsDirty(true) -} - -func (bpv *BufferedElemView) SetSize(size Size) { - bpv.Size = size - bpv.Buffer = nil - bpv.SetIsDirty(true) -} - -// Cursor status pierces the buffered elem view; -// but a few key events are still consumed before the base. -func (bpv *BufferedElemView) SetIsCursor(ic bool) { - bpv.Attrs.SetIsCursor(ic) - bpv.Base.SetIsCursor(ic) -} - -// BufferedElemView's size is simply defined by .Size. -func (bpv *BufferedElemView) Measure() Size { - return bpv.Size -} - -// Renders the elem onto the internal buffer. -// Assumes buffered elem view's elem was already rendered. -// TODO: this function could be optimized to reduce -// redundant background cell modifications. -func (bpv *BufferedElemView) Render() (updated bool) { - if !bpv.GetIsDirty() { - return - } else { - defer bpv.SetIsDirty(false) - } - // Get or initialize buffer. - buffer := bpv.Buffer - if buffer == nil { - buffer = NewBuffer(bpv.Size) - bpv.Buffer = buffer - } - // Reset the buffer's cells. We could - // use Buffer.Reset(), but this helps - // distinguish between undefined cells - // and those of an empty buffer. - for x := 0; x < buffer.Size.Width; x++ { - for y := 0; y < buffer.Size.Height; y++ { - cell := buffer.GetCell(x, y) - cell.Reset() - // Draw Logos star background. - cell.SetValue("\u2606", 1, bpv.Style, bpv) - } - } - // Then, render and draw elem. - bpv.Base.Render() - bpv.Base.Draw(bpv.Offset, buffer.NewView(Coord{})) - return true -} - -func (bpv *BufferedElemView) Draw(offset Coord, view View) { - minX, maxX, minY, maxY := computeIntersection(bpv.Size, offset, view.Bounds) - for y := minY; y < maxY; y++ { - for x := minX; x < maxX; x++ { - bcell := bpv.Buffer.GetCell(x, y) - vcell := view.GetCell(x-offset.X, y-offset.Y) - vcell.SetValueFromCell(bcell) - } - } -} - -func (bpv *BufferedElemView) ProcessEventKey(ev *EventKey) bool { - // Pagination is outer-greedy, and so Logos - // generally just likes infinite areas. - switch evr := ev.Rune(); evr { - case 'a': // left - bpv.Scroll(Coord{16, 0}) - case 's': // down - bpv.Scroll(Coord{0, -8}) - case 'd': // right - bpv.Scroll(Coord{-16, 0}) - case 'w': // up - bpv.Scroll(Coord{0, 8}) - default: - // Try to get the base to handle it. - if bpv.Base.ProcessEventKey(ev) { - return true - } - return false - } - return true // convenience for cases. -} - -func (bpv *BufferedElemView) Scroll(dir Coord) { - bpv.Offset = bpv.Offset.Add(dir) - bpv.SetIsDirty(true) -} diff --git a/misc/logos/cmd/logos.go b/misc/logos/cmd/logos.go deleted file mode 100644 index ddb979111fb..00000000000 --- a/misc/logos/cmd/logos.go +++ /dev/null @@ -1,171 +0,0 @@ -package main - -import ( - "fmt" - "os" - "runtime/debug" - - "github.com/gdamore/tcell/v2" - "github.com/gdamore/tcell/v2/encoding" - "github.com/gnolang/gno/misc/logos" -) - -func main() { - encoding.Register() - - // construct screen - s, e := tcell.NewScreen() - if e != nil { - fmt.Fprintf(os.Stderr, "%v\n", e) - os.Exit(1) - } - // initialize screen - if e = s.Init(); e != nil { - fmt.Fprintf(os.Stderr, "%v\n", e) - os.Exit(1) - } - s.SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorBlack). - Background(tcell.ColorWhite)) - s.Clear() - sw, sh := s.Size() - size := logos.Size{Width: sw, Height: sh} - - // make a buffered stack. - stack := logos.NewStack(size) - stack.PushLayer(makeTestPage()) - bstack := logos.NewBufferedElemView(stack, size) - bstack.Render() - bstack.DrawToScreen(s) - - // recover any panics. - var rec interface{} - var recStack []byte - - // show the screen - quit := make(chan struct{}) - s.Show() - go func() { - // capture panics to print error better. - defer func() { - if rec = recover(); rec != nil { - recStack = debug.Stack() - close(quit) - return - } - }() - // handle event - for { - ev := s.PollEvent() - switch ev := ev.(type) { - case *tcell.EventKey: - switch ev.Key() { - case tcell.KeyCtrlQ: - close(quit) - return - case tcell.KeyCtrlR: - // TODO somehow make it clearer that it happened. - bstack.DrawToScreen(s) - s.Sync() - default: - bstack.ProcessEventKey(ev) - if bstack.Render() { - bstack.DrawToScreen(s) - s.Sync() - } - } - case *tcell.EventResize: - s.Sync() - } - } - }() - - // wait to quit - <-quit - s.Fini() - fmt.Println("charset:", s.CharacterSet()) - fmt.Println("goodbye!") - fmt.Println(bstack.Sprint()) - - if rec != nil { - fmt.Println("====================") - fmt.Println("panic:", rec) - fmt.Println("stacktrace:\n", string(recStack)) - fmt.Println("====================") - } -} - -func makeTestString() string { - s := "" - putln := func(l string) { - s += l + "\n" - } - // putln("Character set: " + s.CharacterSet()) - putln("Press Ctrl-Q to Exit") - putln("English: October") - putln("Icelandic: október") - putln("Arabic: أكتوبر") - putln("Russian: октября") - putln("Greek: Οκτωβρίου") - putln("Chinese: 十月 (note, two double wide characters)") - putln("Combining: A\u030a (should look like Angstrom)") - putln("Emoticon: \U0001f618 (blowing a kiss)") - putln("Airplane: \u2708 (fly away)") - putln("Command: \u2318 (mac clover key)") - putln("Enclose: !\u20e3 (should be enclosed exclamation)") - putln("ZWJ: \U0001f9db\u200d\u2640 (female vampire)") - putln("ZWJ: \U0001f9db\u200d\u2642 (male vampire)") - putln("Family: \U0001f469\u200d\U0001f467\u200d\U0001f467 (woman girl girl)\n") - // XXX why is this broken? - // putln("Region: \U0001f1fa\U0001f1f8 (USA! USA!)\n") - putln("") - putln("Box:") - putln(string([]rune{ - tcell.RuneULCorner, - tcell.RuneHLine, - tcell.RuneTTee, - tcell.RuneHLine, - tcell.RuneURCorner, - })) - putln(string([]rune{ - tcell.RuneVLine, - tcell.RuneBullet, - tcell.RuneVLine, - tcell.RuneLantern, - tcell.RuneVLine, - }) + " (bullet, lantern/section)") - putln(string([]rune{ - tcell.RuneLTee, - tcell.RuneHLine, - tcell.RunePlus, - tcell.RuneHLine, - tcell.RuneRTee, - })) - putln(string([]rune{ - tcell.RuneVLine, - tcell.RuneDiamond, - tcell.RuneVLine, - tcell.RuneUArrow, - tcell.RuneVLine, - }) + " (diamond, up arrow)") - putln(string([]rune{ - tcell.RuneLLCorner, - tcell.RuneHLine, - tcell.RuneBTee, - tcell.RuneHLine, - tcell.RuneLRCorner, - })) - return s -} - -func makeTestPage() *logos.BufferedElemView { - // make a buffered page. - ts := makeTestString() - style := logos.DefaultStyle() - style.Padding = logos.Padding{Left: 2, Top: 2, Right: 2, Bottom: 2} - style.Border = logos.DefaultBorder() - // TODO width shouldn't matter. - page := logos.NewPage(ts, 84, true, style) - bpv := logos.NewBufferedElemView(page, logos.Size{}) - return bpv -} diff --git a/misc/logos/image.png b/misc/logos/image.png deleted file mode 100644 index d6ac0cf3151548ebb46246e1378a1bf9021a34ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 479803 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Η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

6Qj)sR;A%H??dc%Q}%M<|!n8;f3Ui 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

`r82}crg^pS2z%p8h(77XP)P%0lV&sVGvEl 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 z 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

@8ggH6(QbobtoUx5_J36F?Tm=-SEx>hN{WUDq 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 z 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 diff --git a/misc/logos/misc.go b/misc/logos/misc.go deleted file mode 100644 index 4bf3c8c6267..00000000000 --- a/misc/logos/misc.go +++ /dev/null @@ -1,155 +0,0 @@ -package logos - -import ( - "strings" - "unicode" - - "github.com/gdamore/tcell/v2" - runewidth "github.com/mattn/go-runewidth" -) - -// splits a string into lines by newline. -func splitLines(s string) (ss []string) { - return strings.Split(s, "\n") -} - -// splits a string according to unicode spaces. -func splitSpaces(s string) (ss []string) { - buf := []rune{} - for _, r := range s { - if unicode.IsSpace(r) { - // continue - if len(buf) > 0 { - ss = append(ss, string(buf)) - buf = nil - } - } else { - buf = append(buf, r) - } - } - if len(buf) > 0 { - ss = append(ss, string(buf)) - // buf = nil - } - return ss -} - -func toRunes(s string) []rune { - runes := make([]rune, 0, len(s)) - for _, r := range s { - runes = append(runes, r) - } - return runes -} - -// gets the terminal display width of a string. -// must be compatible with nextCharacter(). -// NOTE: must be kept in sync with nextCharacter(); see tests. -func widthOf(s string) (l int) { - zwj := false // zero width joiner '\u200d'. - for _, r := range s { - if r == '\u200d' { - zwj = true - continue - } - if zwj { - zwj = false - continue - } - switch runewidth.RuneWidth(r) { - case 0: - if isCombining(r) { - // combining characters have no length. - } else { - l++ // show a blank instead, weird. - } - case 1: - l++ - case 2: - l += 2 - default: - panic("should not happen") - } - } - return l -} - -// given runes of a valid utf8 string, -// return a string that represents -// the next single character (with any modifiers). -// w: width of character. n: number of runes read -func nextCharacter(rz []rune) (s string, w int, n int) { - for n = 0; n < len(rz); n++ { - r := rz[n] - if r == '\u200d' { - // special case: zero width joins. - s = s + string(r) - if n+1 < len(rz) { - s = s + string(rz[n+1]) - n++ - continue - } else { - // just continue, return invalid string s. - n++ - return - } - } else if 0 < len(s) { - return - } else { - // append r to s and inc w. - rw := runewidth.RuneWidth(r) - s = s + string(r) - if rw == 0 { - if isCombining(r) { - // no width - } else { - w += 1 - } - } else { - w += rw - } - } - } - return -} - -//---------------------------------------- - -func AbsCoord(elem Elem) (crd Coord) { - for elem != nil { - crd = crd.Add(elem.GetCoord()) - elem = elem.GetParent() - } - return -} - -var randColors []Color = []Color{ - tcell.ColorAliceBlue, - tcell.ColorAntiqueWhite, - tcell.ColorAquaMarine, - tcell.ColorAzure, - tcell.ColorBeige, - tcell.ColorBisque, - tcell.ColorBlanchedAlmond, - tcell.ColorBlueViolet, - tcell.ColorBrown, - tcell.ColorBurlyWood, -} - -var rctr = 0 - -func RandColor() Color { - rctr++ - return randColors[rctr%len(randColors)] -} - -func IsInBounds(x, y int, origin Coord, size Size) bool { - if x < origin.X || y < origin.Y { - return false - } - if origin.X+size.Width <= x || - origin.Y+size.Height <= y { - return false - } - return true -} diff --git a/misc/logos/misc_test.go b/misc/logos/misc_test.go deleted file mode 100644 index a147f8b41ea..00000000000 --- a/misc/logos/misc_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package logos - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/gnolang/gno/tm2/pkg/random" -) - -// Tests whether widthOf() and nextCharacter() do the same thing. -func TestStringWidthSlow(t *testing.T) { - t.Skip("test failing") - for n := 1; n < 4; n++ { - bz := make([]byte, n) - for { - width1 := widthOf(string(bz)) - width2 := widthOfSlow(string(bz)) - if width1 == 0 { - if isRepeatedWZJ(bz) { - // these bytes encode one or more U+200D WZJ as UTF8. - } else { - require.Fail(t, fmt.Sprintf("unexpected zero width string for bytes %X", bz)) - } - } else { - require.True(t, 0 < width1, "got zero width for bytes %X", bz) - } - require.Equal(t, width1, width2) - if !incBuffer(bz) { - break - } - } - } -} - -// Same as above but for longer pseudo-random strings. -func TestStringWidthRandom(t *testing.T) { - max := 10 * 1024 * 1024 - for i := 0; i < max; i++ { - if i%(max/80) == 0 { - fmt.Print(".") - } - bz := random.RandBytes(12) - width1 := widthOf(string(bz)) - width2 := widthOfSlow(string(bz)) - if width1 == 0 { - if isRepeatedWZJ(bz) { - // these bytes encode one or more U+200D WZJ as UTF8. - } else { - require.Fail(t, "unexpected zero width string") - } - } else { - require.True(t, 0 < width1, "got zero width for bytes %X", bz) - } - require.Equal(t, width1, width2, - "want %d but got %d the slow way: %X", - width1, width2, bz) - } -} - -// For debugging. -func TestStringWidthDummy(t *testing.T) { - bz := []byte{0x0C, 0x5B, 0x0D, 0xCF, 0xC5, 0xE2, 0x80, 0x8D, 0xC1, 0x32, 0x69, 0x41} - width1 := widthOf(string(bz)) - width2 := widthOfSlow(string(bz)) - if width1 == 0 { - if isRepeatedWZJ(bz) { - // these bytes encode one or more U+200D WZJ as UTF8. - } else { - require.Fail(t, "unexpected zero width string") - } - } else { - require.True(t, 0 < width1, "got zero width for bytes %X", bz) - } - require.Equal(t, width1, width2, - "want %d but got %d the slow way: %X", - width1, width2, bz) -} - -// For debugging. -func TestStringWidthDummy2(t *testing.T) { - t.Skip("test failing") - // NOTE: this is broken in the OSX terminal. This should print a USA flag - // and have width 2, or possibly default to two block letters "U" and "S", - // but my terminal prints a flag of width 1. - bz := []byte("\U0001f1fa\U0001f1f8") - width1 := widthOf(string(bz)) - width2 := widthOfSlow(string(bz)) - require.Equal(t, 1, width1) - require.Equal(t, width1, width2, - "want %d but got %d the slow way: %X", - width1, width2, bz) -} - -func isRepeatedWZJ(bz []byte) bool { - if len(bz)%3 != 0 { - return false - } - // this is U+200D is UTF8. - for i := 0; i < len(bz); i += 3 { - if bz[i] != 0xE2 { - return false - } - if bz[i+1] != 0x80 { - return false - } - if bz[i+2] != 0x8D { - return false - } - } - return true -} - -// get the width of a string using nextCharacter(). -func widthOfSlow(s string) (w int) { - rz := toRunes(s) - for 0 < len(rz) { - _, w2, n := nextCharacter(rz) - if n == 0 { - panic("should not happen") - } - w += w2 - rz = rz[n:] - } - return -} - -//---------------------------------------- -// incBuffer for testing - -// If overflow, bz becomes zero and returns false. -func incBuffer(bz []byte) bool { - for i := 0; i < len(bz); i++ { - if bz[i] == 0xFF { - bz[i] = 0x00 - } else { - bz[i]++ - return true - } - } - return false -} - -func TestIncBuffer1(t *testing.T) { - bz := []byte{0x00} - for i := 0; i < (1<<(1*8))-1; i++ { - require.Equal(t, true, incBuffer(bz)) - require.Equal(t, byte(i+1), bz[0]) - } - require.Equal(t, false, incBuffer(bz)) - require.Equal(t, byte(0x00), bz[0]) -} - -func TestIncBuffer2(t *testing.T) { - bz := []byte{0x00, 0x00} - for i := 0; i < (1<<(2*8))-1; i++ { - require.Equal(t, true, incBuffer(bz)) - require.Equal(t, byte(((i+1)>>0)%256), bz[0]) - require.Equal(t, byte(((i+1)>>8)%256), bz[1]) - } - require.Equal(t, []byte{0xFF, 0xFF}, bz) - require.Equal(t, false, incBuffer(bz)) - require.Equal(t, byte(0x00), bz[0]) - require.Equal(t, byte(0x00), bz[1]) -} diff --git a/misc/logos/stack.go b/misc/logos/stack.go deleted file mode 100644 index 17b18327fd2..00000000000 --- a/misc/logos/stack.go +++ /dev/null @@ -1,160 +0,0 @@ -package logos - -import ( - "fmt" - "strings" - - "github.com/gdamore/tcell/v2" -) - -//---------------------------------------- -// Stack - -// A Stack is like a Page, but it only highlights the top -// element, and dims, occludes, or hides lower elements. A -// Stack is therefore ideal for showing modal views. NOTE: -// While most applications shouldn't, it's perfectly fine to -// embed Stacks within Stacks, or layer them on top within a -// stack. -type Stack struct { - Page // a Stack has the same fields as a page. -} - -func NewStack(size Size) *Stack { - return &Stack{ - Page: Page{ - Size: size, // dontcare. - Elems: nil, // nil layers. - Cursor: -1, - }, - } -} - -func (st *Stack) StringIndented(indent string) string { - elines := []string{} - eindent := indent + " " - for _, elem := range st.Elems { - elines = append(elines, eindent+elem.StringIndented(eindent)) - } - return fmt.Sprintf("Stack%v@%p\n%s", - st.Size, - st, - strings.Join(elines, "\n")) -} - -func (st *Stack) String() string { - return fmt.Sprintf("Stack%v{%d}@%p", - st.Size, - len(st.Elems), - st) -} - -func (st *Stack) PushLayer(layer Elem) { - layer.SetParent(st) - st.Elems = append(st.Elems, layer) - st.Cursor++ - st.SetIsDirty(true) -} - -// A Stack's size is simply determined by its .Size. -func (st *Stack) Measure() Size { - return st.Size -} - -// A Stack's render function behaves the same as a Page's; -// it renders its elements (here, its layers). -func (st *Stack) Render() (updated bool) { - return st.Page.Render() -} - -// Draw the rendered layers onto the view. Any dimming of -// occluded layers must actually stretch in all directions -// infinitely (since we can scroll beyond the bounds of any -// view and we expect the dimming effect to carry while we -// scroll), so the entire view is dimmed first, and then the -// upper-most layer is drawn. -func (st *Stack) Draw(offset Coord, view View) { - // Draw bottom layers. - if 1 < len(st.Elems) { - for _, elem := range st.Elems[:len(st.Elems)-1] { - loffset := offset.Sub(elem.GetCoord()) - elem.Draw(loffset, view) - } - } - if 0 < len(st.Elems) { - last := st.Elems[len(st.Elems)-1] - loffset := offset.Sub(last.GetCoord()) - // Draw occlusion screen on view. - for y := 0; y < view.Bounds.Height; y++ { - for x := 0; x < view.Bounds.Width; x++ { - vcell := view.GetCell(x, y) - inBounds := IsInBounds(x, y, - loffset.Neg(), - last.GetSize()) - if inBounds { - // Reset unsets residual "occluded", - // "cursor", and other attributes from the - // previous layer which are no longer - // relevant. - vcell.Reset() - } else { - vcell.SetIsOccluded(true) - } - } - } - // Draw last (top) layer. - last.Draw(loffset, view) - } else { - // Draw occlusion screen on view. - for y := 0; y < view.Bounds.Height; y++ { - for x := 0; x < view.Bounds.Width; x++ { - vcell := view.GetCell(x, y) - vcell.SetIsOccluded(true) - } - } - } -} - -func (st *Stack) ProcessEventKey(ev *EventKey) bool { - // An empty *Stack is inert. - if len(st.Page.Elems) == 0 { - return false - } - // Try to let the last layer handle it. - last := st.Page.Elems[len(st.Page.Elems)-1] - if last.ProcessEventKey(ev) { - return true - } - // Maybe it's something for the stack. - switch ev.Key() { - case tcell.KeyEsc: - if 1 < len(st.Page.Elems) { - // Pop the last layer. - st.Elems = st.Elems[:len(st.Elems)-1] - st.Cursor-- - st.SetIsDirty(true) - return true - } else { - // Let the last layer stick around. - return false - } - default: - return false - } -} - -// Traverses the inclusive ancestors of elem and returns the -// first *Stack encountered. The purpose of this function is -// to find where to push new layers and modal elements for -// drawing. -func StackOf(elem Elem) *Stack { - for elem != nil { - fmt.Println("StackOf", elem) - if st, ok := elem.(*Stack); ok { - return st - } else { - elem = elem.GetParent() - } - } - return nil // no stack -} diff --git a/misc/logos/types.go b/misc/logos/types.go deleted file mode 100644 index 96e983992eb..00000000000 --- a/misc/logos/types.go +++ /dev/null @@ -1,1006 +0,0 @@ -package logos - -import ( - "fmt" - "strings" - - "github.com/gdamore/tcell/v2" -) - -// ---------------------------------------- -// Page - -// A Page has renderable Elem(ents). -type Page struct { - Coord // used by parent only. TODO document. - Size - *Style - Attrs - Elems []Elem - Cursor int // selected cursor element index, or -1. -} - -// An elem is something that can draw a portion of itself onto -// a view. It has a relative coord and a size. Before it is -// drawn, it is rendered. Measure will update its size, while -// GetSize() returns the cached size. ProcessEventKey() -// returns true if event was consumed. -type Elem interface { - GetParent() Elem - SetParent(Elem) - GetCoord() Coord - SetCoord(Coord) - GetStyle() *Style - SetStyle(*Style) - GetAttrs() *Attrs - GetIsCursor() bool - SetIsCursor(bool) - GetIsDirty() bool - SetIsDirty(bool) - GetIsOccluded() bool - SetIsOccluded(bool) - GetSize() Size - Measure() Size - Render() bool - Draw(offset Coord, dst View) - ProcessEventKey(*EventKey) bool - String() string - StringIndented(indent string) string - // NOTE: SetSize(Size) isn't an elem interface, as - // containers in general can't force elements to be of a - // certain size, but rather prefers drawing out of - // bounds; this opinion may distinguishes Logos from - // other most gui frameworks. -} - -var ( - _ Elem = &Page{} - _ Elem = &BufferedElemView{} - _ Elem = &TextElem{} - _ Elem = &Stack{} -) - -// produces a page from a string. -// width is the width of the page. -// if isCode, width is ignored. -func NewPage(s string, width int, isCode bool, style *Style) *Page { - page := &Page{ - Size: Size{ - Width: width, - Height: -1, // not set - }, - Style: style, - Elems: nil, // will set - Cursor: -1, - } - elems := []Elem{} - if s != "" { - pad := style.GetPadding() - ypos := 0 + pad.Top - xpos := 0 + pad.Left - lines := splitLines(s) - if isCode { - for _, line := range lines { - te := NewTextElem(line, style) - te.SetParent(page) - te.SetCoord(Coord{X: xpos, Y: ypos}) - elems = append(elems, te) - ypos++ - xpos = 0 + pad.Left - } - } else { - for _, line := range lines { - words := splitSpaces(line) - for _, word := range words { - wd := widthOf(word) - if width < xpos+wd+pad.Left+pad.Right { - if xpos != 0+pad.Left { - ypos++ - xpos = 0 + pad.Left - } - } - te := NewTextElem(word, style) - te.SetParent(page) - te.SetCoord(Coord{X: xpos, Y: ypos}) - elems = append(elems, te) - xpos += te.Width // size of word - xpos += 1 // space after each word (not written) - } - ypos++ - xpos = 0 + pad.Left - } - } - } - page.Elems = elems - page.Measure() - page.SetIsDirty(true) - return page -} - -func (pg *Page) StringIndented(indent string) string { - elines := []string{} - eindent := indent + " " - for _, elem := range pg.Elems { - elines = append(elines, eindent+elem.StringIndented(eindent)) - } - return fmt.Sprintf("Page%v@%p\n%s", - pg.Size, - pg, - strings.Join(elines, "\n")) -} - -func (pg *Page) String() string { - return fmt.Sprintf("Page%v{%d}@%p", - pg.Size, len(pg.Elems), pg) -} - -func (pg *Page) NextCoord() Coord { - if len(pg.Elems) == 0 { - return Coord{X: pg.GetPadding().Left, Y: pg.GetPadding().Top} - } else { - last := pg.Elems[len(pg.Elems)-1] - last.Measure() - lcoord := last.GetCoord() - lsize := last.GetSize() - return Coord{ - X: pg.GetPadding().Left, - Y: lcoord.Y + lsize.Height, // no spacers by spec. - } - } -} - -func (pg *Page) SetStyle(style *Style) { - pg.Style = style -} - -// Measures the size of elem and appends to page below the last element, -// or if empty, the top-leftmost coordinate exclusive of padding cells. -func (pg *Page) AppendElem(elem Elem) { - ncoord := pg.NextCoord() - elem.SetParent(pg) - elem.SetCoord(ncoord) - pg.Elems = append(pg.Elems, elem) - pg.SetIsDirty(true) -} - -// Assumes page starts at 0,0. -func (pg *Page) Measure() Size { - pad := pg.GetPadding() - maxX := pad.Left - maxY := pad.Top - for _, view := range pg.Elems { - coord := view.GetCoord() - size := view.GetSize() - if maxX < coord.X+size.Width { - maxX = coord.X + size.Width - } - if maxY < coord.Y+size.Height { - maxY = coord.Y + size.Height - } - } - size := Size{ - Width: maxX + pad.Right, - Height: maxY + pad.Bottom, - } - pg.Size = size - return size -} - -/* - Page draw logic: - Let's say we want to draw a Page. We want to draw it onto - some buffer, or more specially some "view" of a buffer (as - a slice of an array is a view into an array buffer). - - Page virtual bounds: - 0 - - - - - - - - - - + - :\ : - : \ (3,3) : - : @-----------+ : - : |View | : - : | | : - : +-----------+ : - : : - + - - - - - - - - - - + - - 0 is the origin point for the Page. - @ is an offset within the page. @ here is (3,3). - It is where the View is conceptually placed, but - otherwise the View isn't aware where @ is. - This offset is passed in as an argument 'offset'. - - NOTE: Offset is relative in the base page. To offset the - drawing position in the view (e.g. to only write on the - right half of the buffer view), derive another view from - the original. - - The View is associated with an underlying (base) buffer. - - Page virtual bounds: - 0 - - - - - - - - - - + - +=:=====================:===+ <-- underlying Buffer - | : : | - | : @-------------+ : | - | : |View | : | - | : |.Offset=(5,2)| : | - | : +-------------+ : | - | : : | - | + - - - - - - - - - - + | - +===========================+ - - Each element must be drawn onto the buffer view with the - right offset algebra applied. Here is a related diagram - showing the buffer in relation to page elements. - - Page virtual bounds: - 0 - - - - - - - - - - - + - :elem 1 |elem 2 : - : @------------+ : - : |View | : - + - - - | - E - - - -|- + - :elem 3 | |elem 4 | : - : +------------+ : - : | : - + - - - - - - - - - - - + - - In this example the page is composed of four element tiles. - E is elem-4's offset relative to 0, the page's origin. To - draw the top-left portion of elem-4 onto the buffer slice - as shown, the element is drawn with an offset of @-E, which - is negative and indicates that the element should be drawn - offset positively (right and bottom) from @. -*/ - -// Unlike TextElem or BufferedElemView, a Page doesn't keep -// its own buffer. Its render function calls the elements' -// render functions, and the element buffers are combined -// during Draw(). There is a need for distinction because -// Draw() can't be too slow, so Render() is about optimizing -// Draw() calls. The distinction between *Page and -// BufferedElemView gives the user more flexibility. -func (pg *Page) Render() (updated bool) { - if !pg.GetIsDirty() { - return - } else { - defer pg.SetIsDirty(false) - } - for _, elem := range pg.Elems { - elem.Render() - } - return true -} - -// Draw the rendered page elements onto the view. -func (pg *Page) Draw(offset Coord, view View) { - style := pg.GetStyle() - border := style.GetBorder() - minX, maxX, minY, maxY := computeIntersection(pg.Size, offset, view.Bounds) - // First, draw page background style. - for y := minY; y < maxY; y++ { - for x := minX; x < maxX; x++ { - xo, yo := x-offset.X, y-offset.Y - vcell := view.GetCell(xo, yo) - // Draw area and border. - if x == 0 { - if y == pg.Size.Height-1 { - // handle this case first so if height is 1, - // this corner is preferred. - vcell.SetValue(border.BLCorner(), 1, style, pg) - } else if y == 0 { - vcell.SetValue(border.TLCorner(), 1, style, pg) - } else { - vcell.SetValue(border.LeftBorder(y), 1, style, pg) - } - } else if x == pg.Size.Width-1 { - if y == pg.Size.Height-1 { - // ditto for future left-right language support. - vcell.SetValue(border.BRCorner(), 1, style, pg) - } else if y == 0 { - vcell.SetValue(border.TRCorner(), 1, style, pg) - } else { - vcell.SetValue(border.RightBorder(y), 1, style, pg) - } - } else if y == 0 { - vcell.SetValue(border.TopBorder(x), 1, style, pg) - } else if y == pg.Size.Height-1 { - vcell.SetValue(border.BottomBorder(x), 1, style, pg) - } else { // Draw area. - vcell.SetValue(" ", 1, style, pg) - } - } - } - // Then, draw elems. - for _, elem := range pg.Elems { - eoffset := offset.Sub(elem.GetCoord()) - elem.Draw(eoffset, view) - } -} - -type EventKey = tcell.EventKey - -func (pg *Page) ProcessEventKey(ev *EventKey) bool { - switch ev.Key() { - case tcell.KeyEsc: - return false - case tcell.KeyUp: - pg.DecCursor(true) - case tcell.KeyDown: - pg.IncCursor(true) - case tcell.KeyLeft: - pg.DecCursor(false) - case tcell.KeyRight: - pg.IncCursor(false) - case tcell.KeyEnter: - if pg.Cursor == -1 { - // as if pressed down - pg.IncCursor(true) - return true - } - // XXX this is a test. - st := StackOf(pg) - celem := pg.Elems[pg.Cursor] - coord := AbsCoord(celem).Sub(AbsCoord(st)) - page := NewPage("this is a test", 80, false, pg.Style) - coord.Y += 1 - coord.X += 2 - page.SetCoord(coord) - st.PushLayer(page) - default: - return false - } - // Leave as true for convenience in cases above. - // If a key event wasn't consumed, return false. - return true -} - -func (pg *Page) IncCursor(isVertical bool) { - if pg.Cursor == -1 { - if len(pg.Elems) == 0 { - // nothing to select. - } else { - pg.Cursor = 0 - pg.Elems[pg.Cursor].SetIsCursor(true) - } - } else { - pg.Elems[pg.Cursor].SetIsCursor(false) - pg.Cursor++ - if pg.Cursor == len(pg.Elems) { - pg.Cursor = 0 // roll back. - } - pg.Elems[pg.Cursor].SetIsCursor(true) - } -} - -func (pg *Page) DecCursor(isVertical bool) { - if pg.Cursor == -1 { - if len(pg.Elems) == 0 { - // nothing to select. - } else { - pg.Cursor = len(pg.Elems) - 1 - pg.Elems[pg.Cursor].SetIsCursor(true) - } - } else { - pg.Elems[pg.Cursor].SetIsCursor(false) - pg.Cursor-- - if pg.Cursor == -1 { - pg.Cursor = len(pg.Elems) - 1 // roll forward. - } - pg.Elems[pg.Cursor].SetIsCursor(true) - } -} - -// ---------------------------------------- -// TextElem - -type TextElem struct { - Coord - Size - *Style // ignores padding. - Attrs - Text string - *Buffer -} - -func NewTextElem(text string, style *Style) *TextElem { - te := &TextElem{ - Style: style, - Text: text, - Buffer: NewBuffer(Size{ - Height: 1, - Width: widthOf(text), - }), - } - te.Measure() - te.SetIsDirty(true) - return te -} - -func (tel *TextElem) SetStyle(style *Style) { - tel.Style = style -} - -func (tel *TextElem) StringIndented(indent string) string { - return tel.String() -} - -func (tel *TextElem) String() string { - return fmt.Sprintf("Text{%q}", tel.Text) -} - -func (tel *TextElem) Measure() Size { - size := Size{ - Height: 1, - Width: widthOf(tel.Text), - } - tel.Size = size - return size -} - -func (tel *TextElem) Render() (updated bool) { - if tel.Height != 1 { - panic("should not happen") - } - if !tel.GetIsDirty() { - return - } else { - defer tel.SetIsDirty(false) - } - tel.Buffer.Reset() - style := tel.GetStyle() - runes := toRunes(tel.Text) - i := 0 - for 0 < len(runes) { - s, w, n := nextCharacter(runes) - if n == 0 { - panic(fmt.Sprintf( - "unexpected error reading next character from runes %v", - runes)) - } else { - runes = runes[n:] - } - cell := tel.Buffer.GetCell(i, 0) - cell.SetValue(s, w, style, tel) - for j := 1; j < w; j++ { - cell := tel.Buffer.GetCell(i+j, 0) - cell.SetValue("", 0, style, tel) // clear next cells - } - i += w - } - if i != tel.Buffer.Width { - panic(fmt.Sprintf( - "wrote %d cells but there are %d in buffer with text %q", - i, tel.Buffer.Width, tel.Text)) - } - return true -} - -func (tel *TextElem) Draw(offset Coord, view View) { - minX, maxX, minY, maxY := computeIntersection(tel.Size, offset, view.Bounds) - for y := minY; y < maxY; y++ { - if minY != 0 { - panic("should not happen") - } - for x := minX; x < maxX; x++ { - bcell := tel.Buffer.GetCell(x, y) - vcell := view.GetCell(x-offset.X, y-offset.Y) - vcell.SetValueFromCell(bcell) - } - } -} - -func (tel *TextElem) ProcessEventKey(ev *EventKey) bool { - return false // TODO: clipboard. -} - -// ---------------------------------------- -// misc. - -type Color = tcell.Color - -// Style is purely visual and has no side effects. -// It is generally referred to by pointer; you may need to copy before -// modifying. -type Style struct { - Foreground Color - Background Color - Padding Padding - Border Border - StyleFlags - Other []KVPair - CursorStyle *Style -} - -func DefaultStyle() *Style { - return &Style{ - Foreground: gDefaultForeground, - Background: gDefaultBackground, - CursorStyle: &Style{ - Background: tcell.ColorYellow, - }, - } -} - -var ( - gDefaultStyle = DefaultStyle() - gDefaultForeground = tcell.ColorBlack - gDefaultBackground = tcell.ColorLightBlue -) - -func (st *Style) Copy() *Style { - st2 := *st - return &st2 -} - -func (st *Style) GetStyle() *Style { - return st -} - -func (st *Style) GetForeground() Color { - if st == nil { - return gDefaultStyle.Foreground - } else { - return st.Foreground - } -} - -func (st *Style) GetBackground() Color { - if st == nil { - return gDefaultStyle.Background - } else { - return st.Background - } -} - -func (st *Style) GetPadding() Padding { - if st == nil { - return gDefaultStyle.Padding - } else { - return st.Padding - } -} - -func (st *Style) GetBorder() *Border { - if st == nil { - return &gDefaultStyle.Border - } else { - return &st.Border - } -} - -func (st *Style) GetCursorStyle() *Style { - if st == nil { - return gDefaultStyle.CursorStyle - } else if st.CursorStyle == nil { - return st - } else { - return st.CursorStyle - } -} - -// NOTE: this should only be called during the last step when -// writing to screen. The receiver must not be nil and must -// not be modified, and the result is a value, not the style -// of any particular element. -func (st *Style) WithAttrs(attrs *Attrs) (res Style) { - if st == nil { - panic("unexpected nil style") - } - if attrs.GetIsCursor() { - res = *st.GetCursorStyle() - } else { - res = *st - } - if attrs.GetIsOccluded() { - res.SetIsShaded(true) - } - return -} - -func (st Style) GetTStyle() (tst tcell.Style) { - if st.Foreground.Valid() { - tst = tst.Foreground(st.Foreground) - } else { - tst = tst.Foreground(gDefaultForeground) - } - if st.Background.Valid() { - tst = tst.Background(st.Background) - } else { - tst = tst.Background(gDefaultBackground) - } - if st.GetIsShaded() { - tst = tst.Dim(true) - tst = tst.Background(tcell.ColorGray) - } - // TODO StyleFlags - return tst -} - -type StyleFlags uint32 - -func (sf StyleFlags) GetIsDim() bool { - return (sf & StyleFlagDim) != 0 -} - -func (sf *StyleFlags) SetIsDim(id bool) { - if id { - *sf |= StyleFlagDim - } else { - *sf &= ^StyleFlagDim - } -} - -func (sf StyleFlags) GetIsShaded() bool { - return (sf & StyleFlagShaded) != 0 -} - -func (sf *StyleFlags) SetIsShaded(id bool) { - if id { - *sf |= StyleFlagShaded - } else { - *sf &= ^StyleFlagShaded - } -} - -const StyleFlagNone StyleFlags = 0 - -const ( - StyleFlagBold StyleFlags = 1 << iota - StyleFlagDim - StyleFlagShaded - StyleFlagBlink - StyleFlagUnderline - StyleFlagItalic - StyleFlagStrikeThrough -) - -// Attrs have side effects in the Logos system; -// for example, the lone cursor element (one with AttrFlagIsCursor set) -// is where most key events are sent to. -type Attrs struct { - Parent Elem - AttrFlags - Other []KVPair -} - -func (tt *Attrs) GetAttrs() *Attrs { - return tt -} - -func (tt *Attrs) GetParent() Elem { - return tt.Parent -} - -func (tt *Attrs) SetParent(p Elem) { - if tt.Parent != nil && tt.Parent != p { - panic("parent already set") - } - tt.Parent = p -} - -func (tt *Attrs) GetIsCursor() bool { - return (tt.AttrFlags & AttrFlagIsCursor) != 0 -} - -func (tt *Attrs) SetIsCursor(ic bool) { - if ic { - tt.AttrFlags |= AttrFlagIsCursor - } else { - tt.AttrFlags &= ^AttrFlagIsCursor - } - tt.SetIsDirty(true) -} - -func (tt *Attrs) GetIsDirty() bool { - return (tt.AttrFlags & AttrFlagIsDirty) != 0 -} - -func (tt *Attrs) SetIsDirty(id bool) { - if id { - tt.AttrFlags |= AttrFlagIsDirty - if tt.Parent != nil { - tt.Parent.SetIsDirty(true) - } - } else { - tt.AttrFlags &= ^AttrFlagIsDirty - } -} - -func (tt *Attrs) GetIsOccluded() bool { - return (tt.AttrFlags & AttrFlagIsOccluded) != 0 -} - -func (tt *Attrs) SetIsOccluded(ic bool) { - if ic { - tt.AttrFlags |= AttrFlagIsOccluded - } else { - tt.AttrFlags &= ^AttrFlagIsOccluded - } - tt.SetIsDirty(true) -} - -func (tt *Attrs) Merge(ot *Attrs) { - if ot.Parent != nil { - tt.Parent = ot.Parent - } - tt.AttrFlags |= ot.AttrFlags - tt.Other = ot.Other // TODO merge by key. -} - -// ---------------------------------------- -// AttrFlags - -// NOTE: AttrFlags are merged with a simple or-assign op. -type AttrFlags uint32 - -func (af AttrFlags) GetAttrFlags() AttrFlags { - return af -} - -const AttrFlagNone AttrFlags = 0 - -const ( - AttrFlagIsCursor AttrFlags = 1 << iota // is current cursor - AttrFlagIsSelected // is selected (among possibly others) - AttrFlagIsOccluded // is hidden due to stack - AttrFlagIsDirty // is dirty (not yet used) -) - -type KVPair struct { - Key string - Value interface{} -} - -// ---------------------------------------- -// computeIntersection() - -// els: element size -// elo: offset within element -// vws: view size -// minX,maxX,minY,maxY are relative to el. -// maxX and maxY are exclusive. -func computeIntersection(els Size, elo Coord, vws Size) (minX, maxX, minY, maxY int) { - if elo.X < 0 { - /* - View - +----------+ - | [Elem__|____] - +----------+ - x 0 - */ - minX = 0 - } else { - /* - View - +----------+ - [____|__Elem] | - +----------+ - 0 x - */ - minX = elo.X - } - if els.Width <= vws.Width+elo.X { - /* - View - +----------+ - [____|__Elem] | - +----------+ - W w+x - */ - maxX = els.Width - } else { - /* - View - +----------+ - | [Elem__|____] - +----------+ - w+x W - */ - maxX = vws.Width + elo.X - } - if elo.Y < 0 { - minY = 0 - } else { - minY = elo.Y - } - if els.Height <= vws.Height+elo.Y { - maxY = els.Height - } else { - maxY = vws.Height + elo.Y - } - return -} - -// ---------------------------------------- -// Misc simple types - -type Padding struct { - Left int - Top int - Right int - Bottom int -} - -func (pd Padding) GetPadding() Padding { - return pd -} - -// A border can only have width 0 or 1, and is part of the padding. -// Each string should represent a character of width 1. -type Border struct { - Corners [4]string // starts upper-left and clockwise, "" draws no corner. - TopLine []string // nil if no top border. - BotLine []string // nil if no bottom border. - LeftLine []string // nil if no left border. - RightLine []string // nil if no right border. -} - -func DefaultBorder() Border { - return Border{ - Corners: [4]string{ - string(tcell.RuneULCorner), - string(tcell.RuneURCorner), - string(tcell.RuneLRCorner), - string(tcell.RuneLLCorner), - }, - TopLine: []string{string(tcell.RuneHLine)}, - BotLine: []string{string(tcell.RuneHLine)}, - LeftLine: []string{string(tcell.RuneVLine)}, - RightLine: []string{string(tcell.RuneVLine)}, - } -} - -func LeftBorder() Border { - return Border{ - Corners: [4]string{ - string("\u2553"), - "", - "", - string("\u2559"), - }, - LeftLine: []string{ - string("\u2551"), - }, - } -} - -func orSpace(chr string) string { - if chr == "" { - return " " - } else { - return chr - } -} - -func (br *Border) GetCorner(i int) string { - if br == nil { - return " " - } else { - return orSpace(br.Corners[i]) - } -} - -func (br *Border) TLCorner() string { - return br.GetCorner(0) -} - -func (br *Border) TRCorner() string { - return br.GetCorner(1) -} - -func (br *Border) BRCorner() string { - return br.GetCorner(2) -} - -func (br *Border) BLCorner() string { - return br.GetCorner(3) -} - -func (br *Border) TopBorder(x int) string { - if br == nil || br.TopLine == nil { - return " " - } else { - return br.TopLine[x%len(br.TopLine)] - } -} - -func (br *Border) BottomBorder(x int) string { - if br == nil || br.BotLine == nil { - return " " - } else { - return br.BotLine[x%len(br.BotLine)] - } -} - -func (br *Border) LeftBorder(y int) string { - if br == nil || br.LeftLine == nil { - return " " - } else { - return br.LeftLine[y%len(br.LeftLine)] - } -} - -func (br *Border) RightBorder(y int) string { - if br == nil || br.RightLine == nil { - return " " - } else { - return br.RightLine[y%len(br.RightLine)] - } -} - -type Size struct { - Width int - Height int // -1 if not set. -} - -func (sz Size) String() string { - return fmt.Sprintf("{%d,%d}", sz.Width, sz.Height) -} - -func (sz Size) IsZero() bool { - return sz.Width == 0 && sz.Height == 0 -} - -func (sz Size) GetSize() Size { - return sz -} - -// zero widths or heights are valid. -func (sz Size) IsValid() bool { - return 0 <= sz.Width && 0 <= sz.Height -} - -func (sz Size) IsPositive() bool { - return 0 < sz.Width && 0 < sz.Height -} - -func (sz Size) SubCoord(crd Coord) Size { - if !crd.IsNonNegative() { - panic("should not happen") - } - sz2 := Size{ - Width: sz.Width - crd.X, - Height: sz.Height - crd.Y, - } - if !sz2.IsValid() { - panic("should not happen") - } - return sz2 -} - -type Coord struct { - X int - Y int -} - -func (crd Coord) GetCoord() Coord { - return crd -} - -func (crd *Coord) SetCoord(nc Coord) { - *crd = nc -} - -func (crd Coord) IsNonNegative() bool { - return 0 <= crd.X && 0 <= crd.Y -} - -func (crd Coord) Neg() Coord { - return Coord{ - X: -crd.X, - Y: -crd.Y, - } -} - -func (crd Coord) Add(crd2 Coord) Coord { - return Coord{ - X: crd.X + crd2.X, - Y: crd.Y + crd2.Y, - } -} - -func (crd Coord) Sub(crd2 Coord) Coord { - return Coord{ - X: crd.X - crd2.X, - Y: crd.Y - crd2.Y, - } -} diff --git a/misc/logos/types_test.go b/misc/logos/types_test.go deleted file mode 100644 index 5960783dc34..00000000000 --- a/misc/logos/types_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package logos - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestNewPage1(t *testing.T) { - page := NewPage("this is a new string", 40, false, nil) - require.NotNil(t, page) - size := page.Size - require.Equal(t, Size{Width: 20, Height: 1}, size) -} - -func TestNewPage2(t *testing.T) { - page := NewPage("this is a new string", 10, false, nil) - require.NotNil(t, page) - size := page.Size - /* - 0123456789 - this is a - new string - */ - require.Equal(t, Size{Width: 10, Height: 2}, size) - require.Equal(t, Coord{0, 0}, page.Elems[0].GetCoord()) - require.Equal(t, Coord{5, 0}, page.Elems[1].GetCoord()) - require.Equal(t, Coord{8, 0}, page.Elems[2].GetCoord()) - require.Equal(t, Coord{0, 1}, page.Elems[3].GetCoord()) - require.Equal(t, Coord{4, 1}, page.Elems[4].GetCoord()) - require.Equal(t, 5, len(page.Elems)) -} - -func TestNewPageSprint(t *testing.T) { - t.Skip("test failing") - page := NewPage("this is a new string", 10, false, nil) - require.NotNil(t, page) - /* - 0123456789 - this is a - new string - */ - bpv := NewBufferedElemView(page, Size{}) - bpv.Render() - out := bpv.Sprint() - require.Equal(t, "this is a \nnew string", out) -} diff --git a/misc/logos/unicode.go b/misc/logos/unicode.go deleted file mode 100644 index 924edecc2c5..00000000000 --- a/misc/logos/unicode.go +++ /dev/null @@ -1,86 +0,0 @@ -package logos - -func isCombining(r rune) bool { - return inTable(r, combining) -} - -// ---------------------------------------- -// from https://github.com/mattn/go-runewidth -// runewidth doesn't expose whether a character is combining or not. -// TODO might as well fork both runewidth and tcell. - -var combining = table{ - {0x0300, 0x036F}, - {0x0483, 0x0489}, - {0x07EB, 0x07F3}, - {0x0C00, 0x0C00}, - {0x0C04, 0x0C04}, - {0x0D00, 0x0D01}, - {0x135D, 0x135F}, - {0x1A7F, 0x1A7F}, - {0x1AB0, 0x1AC0}, - {0x1B6B, 0x1B73}, - {0x1DC0, 0x1DF9}, - {0x1DFB, 0x1DFF}, - {0x20D0, 0x20F0}, - {0x2CEF, 0x2CF1}, - {0x2DE0, 0x2DFF}, - {0x3099, 0x309A}, - {0xA66F, 0xA672}, - {0xA674, 0xA67D}, - {0xA69E, 0xA69F}, - {0xA6F0, 0xA6F1}, - {0xA8E0, 0xA8F1}, - {0xFE20, 0xFE2F}, - {0x101FD, 0x101FD}, - {0x10376, 0x1037A}, - {0x10EAB, 0x10EAC}, - {0x10F46, 0x10F50}, - {0x11300, 0x11301}, - {0x1133B, 0x1133C}, - {0x11366, 0x1136C}, - {0x11370, 0x11374}, - {0x16AF0, 0x16AF4}, - {0x1D165, 0x1D169}, - {0x1D16D, 0x1D172}, - {0x1D17B, 0x1D182}, - {0x1D185, 0x1D18B}, - {0x1D1AA, 0x1D1AD}, - {0x1D242, 0x1D244}, - {0x1E000, 0x1E006}, - {0x1E008, 0x1E018}, - {0x1E01B, 0x1E021}, - {0x1E023, 0x1E024}, - {0x1E026, 0x1E02A}, - {0x1E8D0, 0x1E8D6}, -} - -type interval struct { - first rune - last rune -} - -type table []interval - -func inTable(r rune, t table) bool { - if r < t[0].first { - return false - } - - bot := 0 - top := len(t) - 1 - for top >= bot { - mid := (bot + top) >> 1 - - switch { - case t[mid].last < r: - bot = mid + 1 - case t[mid].first > r: - top = mid - 1 - default: - return true - } - } - - return false -} From 115417274c4c3dce4a26393755763098e6172a94 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:40:37 -0400 Subject: [PATCH 29/64] chore: remove vmkeeper.maxcycles (#2993) Let's remove the `vn.maxCycles` variable from the VM keeper so that it relies solely on the built-in gas system. `maxCycles` remains an option on `gno.Machine` for blockchainless and gasless experiences. --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> Co-authored-by: Morgan Bazalgette --- contribs/gnodev/pkg/dev/node.go | 7 +- gno.land/pkg/gnoland/app.go | 3 +- gno.land/pkg/gnoland/node_inmemory.go | 10 +- .../pkg/gnoland/{vals.go => validators.go} | 0 gno.land/pkg/sdk/vm/common_test.go | 2 +- gno.land/pkg/sdk/vm/keeper.go | 103 ++++++++---------- 6 files changed, 55 insertions(+), 70 deletions(-) rename gno.land/pkg/gnoland/{vals.go => validators.go} (100%) diff --git a/contribs/gnodev/pkg/dev/node.go b/contribs/gnodev/pkg/dev/node.go index c3e70366fb2..0e1099eef88 100644 --- a/contribs/gnodev/pkg/dev/node.go +++ b/contribs/gnodev/pkg/dev/node.go @@ -565,9 +565,8 @@ func newNodeConfig(tmc *tmcfg.Config, chainid string, appstate gnoland.GnoGenesi } return &gnoland.InMemoryNodeConfig{ - PrivValidator: pv, - TMConfig: tmc, - Genesis: genesis, - GenesisMaxVMCycles: 100_000_000, + PrivValidator: pv, + TMConfig: tmc, + Genesis: genesis, } } diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index 2380658c6e9..ca746dbe386 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -34,7 +34,6 @@ 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 } @@ -88,7 +87,7 @@ 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) + vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr) // Set InitChainer icc := cfg.InitChainerConfig diff --git a/gno.land/pkg/gnoland/node_inmemory.go b/gno.land/pkg/gnoland/node_inmemory.go index d168c955607..f81838e1eb3 100644 --- a/gno.land/pkg/gnoland/node_inmemory.go +++ b/gno.land/pkg/gnoland/node_inmemory.go @@ -20,11 +20,10 @@ import ( ) type InMemoryNodeConfig struct { - PrivValidator bft.PrivValidator // identity of the validator - Genesis *bft.GenesisDoc - TMConfig *tmcfg.Config - GenesisMaxVMCycles int64 - DB *memdb.MemDB // will be initialized if nil + PrivValidator bft.PrivValidator // identity of the validator + Genesis *bft.GenesisDoc + TMConfig *tmcfg.Config + DB *memdb.MemDB // will be initialized if nil // If StdlibDir not set, then it's filepath.Join(TMConfig.RootDir, "gnovm", "stdlibs") InitChainerConfig @@ -106,7 +105,6 @@ func NewInMemoryNode(logger *slog.Logger, cfg *InMemoryNodeConfig) (*node.Node, // Initialize the application with the provided options gnoApp, err := NewAppWithOptions(&AppOptions{ Logger: logger, - MaxCycles: cfg.GenesisMaxVMCycles, DB: cfg.DB, EventSwitch: evsw, InitChainerConfig: cfg.InitChainerConfig, diff --git a/gno.land/pkg/gnoland/vals.go b/gno.land/pkg/gnoland/validators.go similarity index 100% rename from gno.land/pkg/gnoland/vals.go rename to gno.land/pkg/gnoland/validators.go diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index 43a8fe1fbec..66975fba923 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -47,7 +47,7 @@ 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) + vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank) mcw := ms.MultiCacheWrap() vmk.Initialize(log.NewNoopLogger(), mcw) diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 365473b3e7a..f069cce3723 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -62,8 +62,6 @@ type VMKeeper struct { // cached, the DeliverTx persistent state. gnoStore gno.Store - - maxCycles int64 // max allowed cylces on VM executions } // NewVMKeeper returns a new VMKeeper. @@ -72,15 +70,13 @@ func NewVMKeeper( iavlKey store.StoreKey, acck auth.AccountKeeper, bank bank.BankKeeper, - 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, } return vmk } @@ -267,13 +263,12 @@ func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Add m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: store, - Context: msgCtx, - Alloc: store.GetAllocator(), - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: os.Stdout, // XXX + Store: store, + Context: msgCtx, + Alloc: store.GetAllocator(), + GasMeter: ctx.GasMeter(), }) defer m.Release() @@ -368,13 +363,12 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { // Parse and run the files, construct *PV. m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: os.Stdout, // XXX + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + GasMeter: ctx.GasMeter(), }) defer m2.Release() defer func() { @@ -469,13 +463,12 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { // Construct machine and evaluate. m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: gnostore.GetAllocator(), - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: gnostore.GetAllocator(), + GasMeter: ctx.GasMeter(), }) defer m.Release() m.SetActivePackage(mpv) @@ -569,13 +562,12 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { buf := new(bytes.Buffer) m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: buf, - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: buf, + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + GasMeter: ctx.GasMeter(), }) // XXX MsgRun does not have pkgPath. How do we find it on chain? defer m.Release() @@ -596,13 +588,12 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { m2 := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: "", - Output: buf, - Store: gnostore, - Alloc: gnostore.GetAllocator(), - Context: msgCtx, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: "", + Output: buf, + Store: gnostore, + Alloc: gnostore.GetAllocator(), + Context: msgCtx, + GasMeter: ctx.GasMeter(), }) defer m2.Release() m2.SetActivePackage(pv) @@ -728,13 +719,12 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: pkgPath, + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: alloc, + GasMeter: ctx.GasMeter(), }) defer m.Release() defer func() { @@ -795,13 +785,12 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string } m := gno.NewMachineWithOptions( gno.MachineOptions{ - PkgPath: pkgPath, - Output: os.Stdout, // XXX - Store: gnostore, - Context: msgCtx, - Alloc: alloc, - MaxCycles: vm.maxCycles, - GasMeter: ctx.GasMeter(), + PkgPath: pkgPath, + Output: os.Stdout, // XXX + Store: gnostore, + Context: msgCtx, + Alloc: alloc, + GasMeter: ctx.GasMeter(), }) defer m.Release() defer func() { From 47fb38907369e4bc23535d71cda58d78f27bb575 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:09:54 +0200 Subject: [PATCH 30/64] chore(deps): bump the actions group across 1 directory with 2 updates (#2995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the actions group with 2 updates in the / directory: [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) and [anchore/sbom-action](https://github.com/anchore/sbom-action). Updates `sigstore/cosign-installer` from 3.6.0 to 3.7.0

Release notes

Sourced from sigstore/cosign-installer's releases.

v3.7.0

What's Changed

Full Changelog: https://github.com/sigstore/cosign-installer/compare/v3.6.0...v3.7.0

Commits

Updates `anchore/sbom-action` from 0.17.2 to 0.17.5
Release notes

Sourced from anchore/sbom-action's releases.

v0.17.5

Changes in v0.17.5

v0.17.4

Changes in v0.17.4

v0.17.3

Changes in v0.17.3

Commits
  • 1ca97d9 chore(deps): update Syft to v1.14.2 (#503)
  • 8d0a650 chore(deps): update Syft to v1.14.1 (#502)
  • f5e124a chore(deps): bump peter-evans/create-pull-request from 6.1.0 to 7.0.5 (#493)
  • eff08d0 chore: configure changelog-ignore label (#499)
  • 18f9bde chore: remove snapshot tests; fix deprecation errors for outdated packages (#...
  • 2e87236 add release docs (#500)
  • 4a914bc chore(deps): bump actions/checkout from 4.2.0 to 4.2.1 (#497)
  • 8cb9966 chore(deps): update Syft to v1.14.0 (#498)
  • beb779b Update README to include bit about permissions near the top (#496)
  • 87b3137 chore(deps): update Syft to v1.13.0 (#488)
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] --- .github/workflows/nightlies.yml | 4 +-- .github/workflows/releaser-master.yml | 4 +-- .github/workflows/releaser.yml | 4 +-- go.mod | 5 ---- go.sum | 40 --------------------------- 5 files changed, 6 insertions(+), 51 deletions(-) diff --git a/.github/workflows/nightlies.yml b/.github/workflows/nightlies.yml index e8f3fe4ca5c..99f9a406ed1 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.7.0 + - uses: anchore/sbom-action/download-syft@v0.17.5 - uses: docker/login-action@v3 with: diff --git a/.github/workflows/releaser-master.yml b/.github/workflows/releaser-master.yml index 7eda0536532..59dc2ec8705 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.7.0 + - uses: anchore/sbom-action/download-syft@v0.17.5 - uses: docker/login-action@v3 with: diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 5433582cace..4fb3c279b1f 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.7.0 + - uses: anchore/sbom-action/download-syft@v0.17.5 - uses: docker/login-action@v3 with: diff --git a/go.mod b/go.mod index d890ab020a4..33f3a0f5212 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/fortytw2/leaktest v1.3.0 - github.com/gdamore/tcell/v2 v2.7.4 github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 github.com/golang/protobuf v1.5.4 github.com/google/gofuzz v1.2.0 @@ -21,7 +20,6 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/gotuna/gotuna v0.6.0 github.com/libp2p/go-buffer-pool v0.1.0 - github.com/mattn/go-runewidth v0.0.16 github.com/pelletier/go-toml v1.9.5 github.com/peterbourgon/ff/v3 v3.4.0 github.com/pmezard/go-difflib v1.0.0 @@ -53,7 +51,6 @@ require ( require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/gdamore/encoding v1.0.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -61,10 +58,8 @@ require ( 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/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 diff --git a/go.sum b/go.sum index 9495dd5b451..55b5681e559 100644 --- a/go.sum +++ b/go.sum @@ -51,10 +51,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= -github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= -github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= 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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -110,11 +106,6 @@ 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/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-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/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= @@ -136,9 +127,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -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= @@ -156,7 +144,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT 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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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= @@ -190,30 +177,20 @@ 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.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/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/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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.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/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/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -225,36 +202,19 @@ 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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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/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/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/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/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= From 4b6871295b25924e32475bf2b8f90d11377bdd6a Mon Sep 17 00:00:00 2001 From: Jeff Thompson Date: Tue, 22 Oct 2024 13:55:52 +0200 Subject: [PATCH 31/64] fix(crypto/keys): in dbKeybase.writeInfo, if replacing a name entry, remove the lookup by the old address (#2685) This PR fixes the bug demonstrated in https://github.com/gnolang/gno/pull/2684 : * In `dbKeybase.writeInfo`, add an `error` return and propagate this to all callers (`writeLocalKey`, etc.) . We need `writeInfo` to do some database integrity checks, so it needs to be able to return an error. * Update `dbKeybase.writeInfo` as suggested in [#2684](https://github.com/gnolang/gno/pull/2684) . If an existing name entry is being replaced with new `Info`, then remove the "lookup by address" entry for the existing address. * In `TestKeyManagement`, add a test similar to [#2684](https://github.com/gnolang/gno/pull/2684) , except that after using `CreateAccount` with the same name, expect `GetByAddress` to fail for the obsolete address and its (non-existing) public key. (This test passes.)
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests
Signed-off-by: Jeff Thompson --- tm2/pkg/crypto/keys/keybase.go | 58 +++++++++++++++++++---------- tm2/pkg/crypto/keys/keybase_test.go | 13 +++++++ 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/tm2/pkg/crypto/keys/keybase.go b/tm2/pkg/crypto/keys/keybase.go index c28fd1ef952..ea3d0546fa0 100644 --- a/tm2/pkg/crypto/keys/keybase.go +++ b/tm2/pkg/crypto/keys/keybase.go @@ -115,33 +115,32 @@ func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, acco pub := priv.PubKey() // Note: Once Cosmos App v1.3.1 is compulsory, it could be possible to check that pubkey and addr match - return kb.writeLedgerKey(name, pub, *hdPath), nil + return kb.writeLedgerKey(name, pub, *hdPath) } // CreateOffline creates a new reference to an offline keypair. It returns the // created key info. func (kb dbKeybase) CreateOffline(name string, pub crypto.PubKey) (Info, error) { - return kb.writeOfflineKey(name, pub), nil + return kb.writeOfflineKey(name, pub) } // CreateMulti creates a new reference to a multisig (offline) keypair. It // returns the created key info. func (kb dbKeybase) CreateMulti(name string, pub crypto.PubKey) (Info, error) { - return kb.writeMultisigKey(name, pub), nil + return kb.writeMultisigKey(name, pub) } -func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info Info, err error) { +func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (Info, error) { // create master key and derive first key: masterPriv, ch := hd.ComputeMastersFromSeed(seed) derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath) if err != nil { - return + return nil, err } // use possibly blank password to encrypt the private // key and store it. User must enforce good passwords. - info = kb.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd) - return + return kb.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd) } // List returns the keys from storage in alphabetical order. @@ -475,41 +474,60 @@ func (kb dbKeybase) CloseDB() { kb.db.Close() } -func (kb dbKeybase) writeLocalKey(name string, priv crypto.PrivKey, passphrase string) Info { +func (kb dbKeybase) writeLocalKey(name string, priv crypto.PrivKey, passphrase string) (Info, error) { // encrypt private key using passphrase privArmor := armor.EncryptArmorPrivKey(priv, passphrase) // make Info pub := priv.PubKey() info := newLocalInfo(name, pub, privArmor) - kb.writeInfo(name, info) - return info + if err := kb.writeInfo(name, info); err != nil { + return nil, err + } + return info, nil } -func (kb dbKeybase) writeLedgerKey(name string, pub crypto.PubKey, path hd.BIP44Params) Info { +func (kb dbKeybase) writeLedgerKey(name string, pub crypto.PubKey, path hd.BIP44Params) (Info, error) { info := newLedgerInfo(name, pub, path) - kb.writeInfo(name, info) - return info + if err := kb.writeInfo(name, info); err != nil { + return nil, err + } + return info, nil } -func (kb dbKeybase) writeOfflineKey(name string, pub crypto.PubKey) Info { +func (kb dbKeybase) writeOfflineKey(name string, pub crypto.PubKey) (Info, error) { info := newOfflineInfo(name, pub) - kb.writeInfo(name, info) - return info + if err := kb.writeInfo(name, info); err != nil { + return nil, err + } + return info, nil } -func (kb dbKeybase) writeMultisigKey(name string, pub crypto.PubKey) Info { +func (kb dbKeybase) writeMultisigKey(name string, pub crypto.PubKey) (Info, error) { info := NewMultiInfo(name, pub) - kb.writeInfo(name, info) - return info + if err := kb.writeInfo(name, info); err != nil { + return nil, err + } + return info, nil } -func (kb dbKeybase) writeInfo(name string, info Info) { +func (kb dbKeybase) writeInfo(name string, info Info) error { // write the info by key key := infoKey(name) + oldInfob := kb.db.Get(key) + if len(oldInfob) > 0 { + // Enforce 1-to-1 name to address. Remove the lookup by the old address + oldInfo, err := readInfo(oldInfob) + if err != nil { + return err + } + kb.db.DeleteSync(addrKey(oldInfo.GetAddress())) + } + serializedInfo := writeInfo(info) kb.db.SetSync(key, serializedInfo) // store a pointer to the infokey by address for fast lookup kb.db.SetSync(addrKey(info.GetAddress()), key) + return nil } func addrKey(address crypto.Address) []byte { diff --git a/tm2/pkg/crypto/keys/keybase_test.go b/tm2/pkg/crypto/keys/keybase_test.go index afcc1c56197..bfb21b46fad 100644 --- a/tm2/pkg/crypto/keys/keybase_test.go +++ b/tm2/pkg/crypto/keys/keybase_test.go @@ -111,6 +111,19 @@ func TestKeyManagement(t *testing.T) { require.NoError(t, err) require.Equal(t, 1, len(keyS)) + // Lookup by original i2 address + infoByAddress, err := cstore.GetByAddress(i2.GetAddress()) + require.NoError(t, err) + // GetByAddress should return Info with the corresponding public key + require.Equal(t, infoByAddress.GetPubKey(), i2.GetPubKey()) + // Replace n2 with a new address + mn2New := `fancy assault crane note start invite ladder ordinary gold amateur check cousin text mercy speak chuckle wine raw chief isolate swallow cushion wrist piece` + _, err = cstore.CreateAccount(n2, mn2New, bip39Passphrase, p2, 0, 0) + require.NoError(t, err) + // Check that CreateAccount removes the entry for the original address (public key) + _, err = cstore.GetByAddress(i2.GetAddress()) + require.NotNil(t, err) + // addr cache gets nuked - and test skip flag err = cstore.Delete(n2, "", true) require.NoError(t, err) From ec222ec8086bc07139bbdf9ef9e9448eaded5f52 Mon Sep 17 00:00:00 2001 From: Stefan Nikolic Date: Tue, 22 Oct 2024 15:35:43 +0200 Subject: [PATCH 32/64] feat(examples): add interactive realm `r/stefann/home` (#2918) # Description: This PR finalizes the core functionality of my home realm project, focusing on a dynamic and interactive home realm experience, driven by GNOT donations. The following key features and enhancements are introduced in this PR: ## Key Features: - **Dynamic Background Change:** - Implemented sequential background changes triggered by GNOT donations. Each donation updates the city background in a fixed order, cycling through a predefined set of cities. The background change is seamless, offering a "traveling" experience for donors. - **Sponsor Leaderboard:** - Added a sponsor leaderboard to showcase the top contributors based on their GNOT donations. The list displays the addresses of the top sponsors, formatted for readability (first and last characters with ellipses), and limits the displayed sponsors to the configurable `maxSponsors` setting. - **Donation Validation:** - Introduced a strict GNOT validation check. The system now rejects any donation attempts that don't include GNOT, ensuring only valid contributions update the state of the realm. - **Owner Withdrawal of Donations:** - Implemented a feature that allows the realm owner to withdraw accumulated GNOT donations, providing control over the funds contributed by supporters. - **Home Realm Configurations:** - **Cities:** Cities can be dynamically updated to refresh the possible backgrounds. - **Maximum Sponsors:** Admins can configure the number of sponsors shown on the leaderboard with the `maxSponsors` setting. - **Jar Link:** Admins can update the link to the donation jar. --- examples/gno.land/r/stefann/home/gno.mod | 9 + examples/gno.land/r/stefann/home/home.gno | 303 ++++++++++++++++++ .../gno.land/r/stefann/home/home_test.gno | 291 +++++++++++++++++ examples/gno.land/r/stefann/registry/gno.mod | 3 + .../gno.land/r/stefann/registry/registry.gno | 51 +++ 5 files changed, 657 insertions(+) create mode 100644 examples/gno.land/r/stefann/home/gno.mod create mode 100644 examples/gno.land/r/stefann/home/home.gno create mode 100644 examples/gno.land/r/stefann/home/home_test.gno create mode 100644 examples/gno.land/r/stefann/registry/gno.mod create mode 100644 examples/gno.land/r/stefann/registry/registry.gno diff --git a/examples/gno.land/r/stefann/home/gno.mod b/examples/gno.land/r/stefann/home/gno.mod new file mode 100644 index 00000000000..dd556e7f817 --- /dev/null +++ b/examples/gno.land/r/stefann/home/gno.mod @@ -0,0 +1,9 @@ +module gno.land/r/stefann/home + +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/ufmt v0.0.0-latest + gno.land/r/stefann/registry v0.0.0-latest +) diff --git a/examples/gno.land/r/stefann/home/home.gno b/examples/gno.land/r/stefann/home/home.gno new file mode 100644 index 00000000000..f40329ebf7e --- /dev/null +++ b/examples/gno.land/r/stefann/home/home.gno @@ -0,0 +1,303 @@ +package home + +import ( + "sort" + "std" + "strings" + + "gno.land/p/demo/avl" + "gno.land/p/demo/ownable" + "gno.land/p/demo/ufmt" + + "gno.land/r/stefann/registry" +) + +type City struct { + Name string + URL string +} + +type Sponsor struct { + Address std.Address + Amount std.Coins +} + +type Profile struct { + pfp string + aboutMe []string +} + +type Travel struct { + cities []City + currentCityIndex int + jarLink string +} + +type Sponsorship struct { + maxSponsors int + sponsors *avl.Tree + DonationsCount int + sponsorsCount int +} + +var ( + profile Profile + travel Travel + sponsorship Sponsorship + owner *ownable.Ownable +) + +func init() { + owner = ownable.NewWithAddress(registry.MainAddr()) + + profile = Profile{ + pfp: "https://i.ibb.co/Bc5YNCx/DSC-0095a.jpg", + aboutMe: []string{ + `### About Me`, + `Hey there! I’m Stefan, a student of Computer Science. I’m all about exploring and adventure — whether it’s diving into the latest tech or discovering a new city, I’m always up for the challenge!`, + + `### Contributions`, + `I'm just getting started, but you can follow my journey through Gno.land right [here](https://github.com/gnolang/hackerspace/issues/94) 🔗`, + }, + } + + travel = Travel{ + cities: []City{ + {Name: "Venice", URL: "https://i.ibb.co/1mcZ7b1/venice.jpg"}, + {Name: "Tokyo", URL: "https://i.ibb.co/wNDJv3H/tokyo.jpg"}, + {Name: "São Paulo", URL: "https://i.ibb.co/yWMq2Sn/sao-paulo.jpg"}, + {Name: "Toronto", URL: "https://i.ibb.co/pb95HJB/toronto.jpg"}, + {Name: "Bangkok", URL: "https://i.ibb.co/pQy3w2g/bangkok.jpg"}, + {Name: "New York", URL: "https://i.ibb.co/6JWLm0h/new-york.jpg"}, + {Name: "Paris", URL: "https://i.ibb.co/q9vf6Hs/paris.jpg"}, + {Name: "Kandersteg", URL: "https://i.ibb.co/60DzywD/kandersteg.jpg"}, + {Name: "Rothenburg", URL: "https://i.ibb.co/cr8d2rQ/rothenburg.jpg"}, + {Name: "Capetown", URL: "https://i.ibb.co/bPGn0v3/capetown.jpg"}, + {Name: "Sydney", URL: "https://i.ibb.co/TBNzqfy/sydney.jpg"}, + {Name: "Oeschinen Lake", URL: "https://i.ibb.co/QJQwp2y/oeschinen-lake.jpg"}, + {Name: "Barra Grande", URL: "https://i.ibb.co/z4RXKc1/barra-grande.jpg"}, + {Name: "London", URL: "https://i.ibb.co/CPGtvgr/london.jpg"}, + }, + currentCityIndex: 0, + jarLink: "https://TODO", // This value should be injected through UpdateJarLink after deployment. + } + + sponsorship = Sponsorship{ + maxSponsors: 5, + sponsors: avl.NewTree(), + DonationsCount: 0, + sponsorsCount: 0, + } +} + +func UpdateCities(newCities []City) { + owner.AssertCallerIsOwner() + travel.cities = newCities +} + +func AddCities(newCities ...City) { + owner.AssertCallerIsOwner() + + travel.cities = append(travel.cities, newCities...) +} + +func UpdateJarLink(newLink string) { + owner.AssertCallerIsOwner() + travel.jarLink = newLink +} + +func UpdatePFP(url string) { + owner.AssertCallerIsOwner() + profile.pfp = url +} + +func UpdateAboutMe(aboutMeStr string) { + owner.AssertCallerIsOwner() + profile.aboutMe = strings.Split(aboutMeStr, "|") +} + +func AddAboutMeRows(newRows ...string) { + owner.AssertCallerIsOwner() + + profile.aboutMe = append(profile.aboutMe, newRows...) +} + +func UpdateMaxSponsors(newMax int) { + owner.AssertCallerIsOwner() + if newMax <= 0 { + panic("maxSponsors must be greater than zero") + } + sponsorship.maxSponsors = newMax +} + +func Donate() { + address := std.GetOrigCaller() + amount := std.GetOrigSend() + + if amount.AmountOf("ugnot") == 0 { + panic("Donation must include GNOT") + } + + existingAmount, exists := sponsorship.sponsors.Get(address.String()) + if exists { + updatedAmount := existingAmount.(std.Coins).Add(amount) + sponsorship.sponsors.Set(address.String(), updatedAmount) + } else { + sponsorship.sponsors.Set(address.String(), amount) + sponsorship.sponsorsCount++ + } + + travel.currentCityIndex++ + sponsorship.DonationsCount++ + + banker := std.GetBanker(std.BankerTypeRealmSend) + ownerAddr := registry.MainAddr() + banker.SendCoins(std.CurrentRealm().Addr(), ownerAddr, banker.GetCoins(std.CurrentRealm().Addr())) +} + +type SponsorSlice []Sponsor + +func (s SponsorSlice) Len() int { + return len(s) +} + +func (s SponsorSlice) Less(i, j int) bool { + return s[i].Amount.AmountOf("ugnot") > s[j].Amount.AmountOf("ugnot") +} + +func (s SponsorSlice) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func GetTopSponsors() []Sponsor { + var sponsorSlice SponsorSlice + + sponsorship.sponsors.Iterate("", "", func(key string, value interface{}) bool { + addr := std.Address(key) + amount := value.(std.Coins) + sponsorSlice = append(sponsorSlice, Sponsor{Address: addr, Amount: amount}) + return false + }) + + sort.Sort(sponsorSlice) + return sponsorSlice +} + +func GetTotalDonations() int { + total := 0 + sponsorship.sponsors.Iterate("", "", func(key string, value interface{}) bool { + total += int(value.(std.Coins).AmountOf("ugnot")) + return false + }) + return total +} + +func Render(path string) string { + out := ufmt.Sprintf("# Exploring %s!\n\n", travel.cities[travel.currentCityIndex].Name) + + out += renderAboutMe() + out += "\n\n" + out += renderTips() + + return out +} + +func renderAboutMe() string { + out := "
" + + out += "
\n\n" + + out += ufmt.Sprintf("
\n\n", travel.cities[travel.currentCityIndex%len(travel.cities)].URL) + + out += ufmt.Sprintf("my profile pic\n\n", profile.pfp) + + out += "
\n\n" + + for _, rows := range profile.aboutMe { + out += "
\n\n" + out += rows + "\n\n" + out += "
\n\n" + } + + out += "
\n\n" + + return out +} + +func renderTips() string { + out := `
` + "\n\n" + + out += `
` + "\n" + + out += `

Help Me Travel The World

` + "\n\n" + + out += renderTipsJar() + "\n" + + out += ufmt.Sprintf(`I am currently in %s,
tip the jar to send me somewhere else!
`, travel.cities[travel.currentCityIndex].Name) + + out += `
Click the jar, tip in GNOT coins, and watch my background change as I head to a new adventure!

` + "\n\n" + + out += renderSponsors() + + out += `
` + "\n\n" + + out += `
` + "\n" + + return out +} + +func formatAddress(address string) string { + if len(address) <= 8 { + return address + } + return address[:4] + "..." + address[len(address)-4:] +} + +func renderSponsors() string { + out := `

Sponsor Leaderboard

` + "\n" + + if sponsorship.sponsorsCount == 0 { + return out + `

No sponsors yet. Be the first to tip the jar!

` + "\n" + } + + topSponsors := GetTopSponsors() + numSponsors := len(topSponsors) + if numSponsors > sponsorship.maxSponsors { + numSponsors = sponsorship.maxSponsors + } + + out += `
    ` + "\n" + + for i := 0; i < numSponsors; i++ { + sponsor := topSponsors[i] + isLastItem := (i == numSponsors-1) + + padding := "10px 5px" + border := "border-bottom: 1px solid #ddd;" + + if isLastItem { + padding = "8px 5px" + border = "" + } + + out += ufmt.Sprintf( + `
  • + %d. %s + %s +
  • `, + padding, border, i+1, formatAddress(sponsor.Address.String()), sponsor.Amount.String(), + ) + } + + return out +} + +func renderTipsJar() string { + out := ufmt.Sprintf(``, travel.jarLink) + "\n" + + out += `Tips Jar` + "\n" + + out += `` + "\n" + + return out +} diff --git a/examples/gno.land/r/stefann/home/home_test.gno b/examples/gno.land/r/stefann/home/home_test.gno new file mode 100644 index 00000000000..ca146b9eb13 --- /dev/null +++ b/examples/gno.land/r/stefann/home/home_test.gno @@ -0,0 +1,291 @@ +package home + +import ( + "std" + "strings" + "testing" + + "gno.land/p/demo/avl" + "gno.land/p/demo/testutils" +) + +func TestUpdatePFP(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + profile.pfp = "" + + UpdatePFP("https://example.com/pic.png") + + if profile.pfp != "https://example.com/pic.png" { + t.Fatalf("expected pfp to be https://example.com/pic.png, got %s", profile.pfp) + } +} + +func TestUpdateAboutMe(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + profile.aboutMe = []string{} + + UpdateAboutMe("This is my new bio.|I love coding!") + + expected := []string{"This is my new bio.", "I love coding!"} + + if len(profile.aboutMe) != len(expected) { + t.Fatalf("expected aboutMe to have length %d, got %d", len(expected), len(profile.aboutMe)) + } + + for i := range profile.aboutMe { + if profile.aboutMe[i] != expected[i] { + t.Fatalf("expected aboutMe[%d] to be %s, got %s", i, expected[i], profile.aboutMe[i]) + } + } +} + +func TestUpdateCities(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + travel.cities = []City{} + + newCities := []City{ + {Name: "Berlin", URL: "https://example.com/berlin.jpg"}, + {Name: "Vienna", URL: "https://example.com/vienna.jpg"}, + } + + UpdateCities(newCities) + + if len(travel.cities) != 2 { + t.Fatalf("expected 2 cities, got %d", len(travel.cities)) + } + + if travel.cities[0].Name != "Berlin" || travel.cities[1].Name != "Vienna" { + t.Fatalf("expected cities to be updated to Berlin and Vienna, got %+v", travel.cities) + } +} + +func TestUpdateJarLink(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + travel.jarLink = "" + + UpdateJarLink("https://example.com/jar") + + if travel.jarLink != "https://example.com/jar" { + t.Fatalf("expected jarLink to be https://example.com/jar, got %s", travel.jarLink) + } +} + +func TestUpdateMaxSponsors(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + sponsorship.maxSponsors = 0 + + UpdateMaxSponsors(10) + + if sponsorship.maxSponsors != 10 { + t.Fatalf("expected maxSponsors to be 10, got %d", sponsorship.maxSponsors) + } + + defer func() { + if r := recover(); r == nil { + t.Fatalf("expected panic for setting maxSponsors to 0") + } + }() + UpdateMaxSponsors(0) +} + +func TestAddCities(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + travel.cities = []City{} + + AddCities(City{Name: "Berlin", URL: "https://example.com/berlin.jpg"}) + + if len(travel.cities) != 1 { + t.Fatalf("expected 1 city, got %d", len(travel.cities)) + } + if travel.cities[0].Name != "Berlin" || travel.cities[0].URL != "https://example.com/berlin.jpg" { + t.Fatalf("expected city to be Berlin, got %+v", travel.cities[0]) + } + + AddCities( + City{Name: "Paris", URL: "https://example.com/paris.jpg"}, + City{Name: "Tokyo", URL: "https://example.com/tokyo.jpg"}, + ) + + if len(travel.cities) != 3 { + t.Fatalf("expected 3 cities, got %d", len(travel.cities)) + } + if travel.cities[1].Name != "Paris" || travel.cities[2].Name != "Tokyo" { + t.Fatalf("expected cities to be Paris and Tokyo, got %+v", travel.cities[1:]) + } +} + +func TestAddAboutMeRows(t *testing.T) { + var owner = std.Address("g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8") + std.TestSetOrigCaller(owner) + + profile.aboutMe = []string{} + + AddAboutMeRows("I love exploring new technologies!") + + if len(profile.aboutMe) != 1 { + t.Fatalf("expected 1 aboutMe row, got %d", len(profile.aboutMe)) + } + if profile.aboutMe[0] != "I love exploring new technologies!" { + t.Fatalf("expected first aboutMe row to be 'I love exploring new technologies!', got %s", profile.aboutMe[0]) + } + + AddAboutMeRows("Travel is my passion!", "Always learning.") + + if len(profile.aboutMe) != 3 { + t.Fatalf("expected 3 aboutMe rows, got %d", len(profile.aboutMe)) + } + if profile.aboutMe[1] != "Travel is my passion!" || profile.aboutMe[2] != "Always learning." { + t.Fatalf("expected aboutMe rows to be 'Travel is my passion!' and 'Always learning.', got %+v", profile.aboutMe[1:]) + } +} + +func TestDonate(t *testing.T) { + var user = testutils.TestAddress("user") + std.TestSetOrigCaller(user) + + sponsorship.sponsors = avl.NewTree() + sponsorship.DonationsCount = 0 + sponsorship.sponsorsCount = 0 + travel.currentCityIndex = 0 + + coinsSent := std.NewCoins(std.NewCoin("ugnot", 500)) + std.TestSetOrigSend(coinsSent, std.NewCoins()) + Donate() + + existingAmount, exists := sponsorship.sponsors.Get(string(user)) + if !exists { + t.Fatalf("expected sponsor to be added, but it was not found") + } + + if existingAmount.(std.Coins).AmountOf("ugnot") != 500 { + t.Fatalf("expected donation amount to be 500ugnot, got %d", existingAmount.(std.Coins).AmountOf("ugnot")) + } + + if sponsorship.DonationsCount != 1 { + t.Fatalf("expected DonationsCount to be 1, got %d", sponsorship.DonationsCount) + } + + if sponsorship.sponsorsCount != 1 { + t.Fatalf("expected sponsorsCount to be 1, got %d", sponsorship.sponsorsCount) + } + + if travel.currentCityIndex != 1 { + t.Fatalf("expected currentCityIndex to be 1, got %d", travel.currentCityIndex) + } + + coinsSent = std.NewCoins(std.NewCoin("ugnot", 300)) + std.TestSetOrigSend(coinsSent, std.NewCoins()) + Donate() + + existingAmount, exists = sponsorship.sponsors.Get(string(user)) + if !exists { + t.Fatalf("expected sponsor to exist after second donation, but it was not found") + } + + if existingAmount.(std.Coins).AmountOf("ugnot") != 800 { + t.Fatalf("expected total donation amount to be 800ugnot, got %d", existingAmount.(std.Coins).AmountOf("ugnot")) + } + + if sponsorship.DonationsCount != 2 { + t.Fatalf("expected DonationsCount to be 2 after second donation, got %d", sponsorship.DonationsCount) + } + + if travel.currentCityIndex != 2 { + t.Fatalf("expected currentCityIndex to be 2 after second donation, got %d", travel.currentCityIndex) + } +} + +func TestGetTopSponsors(t *testing.T) { + var user = testutils.TestAddress("user") + std.TestSetOrigCaller(user) + + sponsorship.sponsors = avl.NewTree() + sponsorship.sponsorsCount = 0 + + sponsorship.sponsors.Set("g1address1", std.NewCoins(std.NewCoin("ugnot", 300))) + sponsorship.sponsors.Set("g1address2", std.NewCoins(std.NewCoin("ugnot", 500))) + sponsorship.sponsors.Set("g1address3", std.NewCoins(std.NewCoin("ugnot", 200))) + sponsorship.sponsorsCount = 3 + + topSponsors := GetTopSponsors() + + if len(topSponsors) != 3 { + t.Fatalf("expected 3 sponsors, got %d", len(topSponsors)) + } + + if topSponsors[0].Address.String() != "g1address2" || topSponsors[0].Amount.AmountOf("ugnot") != 500 { + t.Fatalf("expected top sponsor to be g1address2 with 500ugnot, got %s with %dugnot", topSponsors[0].Address.String(), topSponsors[0].Amount.AmountOf("ugnot")) + } + + if topSponsors[1].Address.String() != "g1address1" || topSponsors[1].Amount.AmountOf("ugnot") != 300 { + t.Fatalf("expected second sponsor to be g1address1 with 300ugnot, got %s with %dugnot", topSponsors[1].Address.String(), topSponsors[1].Amount.AmountOf("ugnot")) + } + + if topSponsors[2].Address.String() != "g1address3" || topSponsors[2].Amount.AmountOf("ugnot") != 200 { + t.Fatalf("expected third sponsor to be g1address3 with 200ugnot, got %s with %dugnot", topSponsors[2].Address.String(), topSponsors[2].Amount.AmountOf("ugnot")) + } +} + +func TestGetTotalDonations(t *testing.T) { + var user = testutils.TestAddress("user") + std.TestSetOrigCaller(user) + + sponsorship.sponsors = avl.NewTree() + sponsorship.sponsorsCount = 0 + + sponsorship.sponsors.Set("g1address1", std.NewCoins(std.NewCoin("ugnot", 300))) + sponsorship.sponsors.Set("g1address2", std.NewCoins(std.NewCoin("ugnot", 500))) + sponsorship.sponsors.Set("g1address3", std.NewCoins(std.NewCoin("ugnot", 200))) + sponsorship.sponsorsCount = 3 + + totalDonations := GetTotalDonations() + + if totalDonations != 1000 { + t.Fatalf("expected total donations to be 1000ugnot, got %dugnot", totalDonations) + } +} + +func TestRender(t *testing.T) { + travel.currentCityIndex = 0 + travel.cities = []City{ + {Name: "Venice", URL: "https://example.com/venice.jpg"}, + {Name: "Paris", URL: "https://example.com/paris.jpg"}, + } + + output := Render("") + + expectedCity := "Venice" + if !strings.Contains(output, expectedCity) { + t.Fatalf("expected output to contain city name '%s', got %s", expectedCity, output) + } + + expectedURL := "https://example.com/venice.jpg" + if !strings.Contains(output, expectedURL) { + t.Fatalf("expected output to contain city URL '%s', got %s", expectedURL, output) + } + + travel.currentCityIndex = 1 + output = Render("") + + expectedCity = "Paris" + if !strings.Contains(output, expectedCity) { + t.Fatalf("expected output to contain city name '%s', got %s", expectedCity, output) + } + + expectedURL = "https://example.com/paris.jpg" + if !strings.Contains(output, expectedURL) { + t.Fatalf("expected output to contain city URL '%s', got %s", expectedURL, output) + } +} diff --git a/examples/gno.land/r/stefann/registry/gno.mod b/examples/gno.land/r/stefann/registry/gno.mod new file mode 100644 index 00000000000..5ed3e4916e2 --- /dev/null +++ b/examples/gno.land/r/stefann/registry/gno.mod @@ -0,0 +1,3 @@ +module gno.land/r/stefann/registry + +require gno.land/p/demo/ownable v0.0.0-latest diff --git a/examples/gno.land/r/stefann/registry/registry.gno b/examples/gno.land/r/stefann/registry/registry.gno new file mode 100644 index 00000000000..6f56d105e4b --- /dev/null +++ b/examples/gno.land/r/stefann/registry/registry.gno @@ -0,0 +1,51 @@ +package registry + +import ( + "errors" + "std" + + "gno.land/p/demo/ownable" +) + +var ( + mainAddr std.Address + backupAddr std.Address + owner *ownable.Ownable +) + +func init() { + mainAddr = "g1sd5ezmxt4rwpy52u6wl3l3y085n8x0p6nllxm8" + backupAddr = "g13awn2575t8s2vf3svlprc4dg0e9z5wchejdxk8" + + owner = ownable.NewWithAddress(mainAddr) +} + +func MainAddr() std.Address { + return mainAddr +} + +func BackupAddr() std.Address { + return backupAddr +} + +func SetMainAddr(addr std.Address) error { + if !addr.IsValid() { + return errors.New("config: invalid address") + } + + owner.AssertCallerIsOwner() + + mainAddr = addr + return nil +} + +func SetBackupAddr(addr std.Address) error { + if !addr.IsValid() { + return errors.New("config: invalid address") + } + + owner.AssertCallerIsOwner() + + backupAddr = addr + return nil +} From 5c876f3787493158faf38b6cc7d28b2d57e417b1 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:45:11 -0400 Subject: [PATCH 33/64] chore(codecov): ignore generated files (#2998) The change does not appear to be applied to my PR #2920, so I am opening a dedicated PR to make Codecov aware. Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .github/codecov.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/codecov.yml b/.github/codecov.yml index ea1c701d946..d1ecba7ade3 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -39,3 +39,8 @@ flag_management: - type: patch target: auto # Let's decrease this later. threshold: 10 + +ignore: + - "gnovm/stdlibs/generated.go" + - "gnovm/tests/stdlibs/generated.go" + - "**/*.pb.go" From 1a57e81f5e454304dd0de38657d680edef18100d Mon Sep 17 00:00:00 2001 From: Jae Kwon <53785+jaekwon@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:38:00 -0700 Subject: [PATCH 34/64] feat(gnovm): handle loop variables (#2429) # Problem Definition The problem originates from the issue described in [#1135](https://github.com/gnolang/gno/issues/1135). While the full scope of the issue is broader, it fundamentally relates to the concept of loop variable escapes block where it's defined. e.g. 1: ```go package main import "fmt" var s1 []*int func forLoopRef() { defer func() { for i, e := range s1 { fmt.Printf("s1[%d] is: %d\n", i, *e) } }() for i := 0; i < 3; i++ { z := i + 1 s1 = append(s1, &z) } } func main() { forLoopRef() } ``` e.g. 2: ```go package main type f func() var fs []f func forLoopClosure() { defer func() { for _, f := range fs { f() } }() for i := 0; i < 3; i++ { z := i fs = append(fs, func() { println(z) }) } } func main() { forLoopClosure() } ``` e.g. 3: ```go package main func main() { c := 0 closures := []func(){} loop: i := c closures = append(closures, func() { println(i) }) c += 1 if c < 10 { goto loop } for _, cl := range closures { cl() } } ``` # Solution ideas - **identify escaped vars in preprocess**: Detect situations where a loop variable is defined within a loop block(including `for/range` loops or loops constructed using `goto` statements), and escapes the block where it's defined. - **runtime allocation**: Allocate a new heap item for the loop variable in each iteration to ensure each iteration operates with its unique variable instance. - **NOTE1**: this is consistent with Go's Strategy: "Each iteration has its own separate declared variable (or variables) [Go 1.22]. The variable used by the first iteration is declared by the init statement. The variable used by each subsequent iteration is declared implicitly before executing the post statement and initialized to the value of the previous iteration's variable at that moment." - **NOTE2**: the `loopvar` feature of Go 1.22 is not supported in this version, and will be supported in next version. not supporting capture `i` defined in for/range clause; ```go for i := 0; i < 3; i++ { s1 = append(s1, &i) } ``` # Implementation Details **Preprocess Stage(Multi-Phase Preprocessor)**: - **Phase 1: `initStaticBlocks`**: Establish a cascading scope structure where `predefine` is conducted. In this phase Name expressions are initially marked as `NameExprTypeDefine`, which may later be upgraded to `NameExprTypeHeapDefine` if it is determined that they escape the loop block. This phase also supports other processes as a prerequisite[#2077](https://github.com/gnolang/gno/pull/2077). - **Phase 2: `preprocess1`**: This represents the original preprocessing phase(not going into details). - **Phase 3: `findGotoLoopDefines`**: By traversing the AST, any name expression defined in a loop block (for/range, goto) with the attribute `NameExprTypeDefine` is promoted to `NameExprTypeHeapDefine`. This is used in later phase. - **Phase 4: `findLoopUses1`**: Identify the usage of `NameExprTypeHeapDefine` name expressions. If a name expression is used in a function literal or is referrnced(e.g. &a), and it was previously defined as `NameExprTypeHeapDefine`, the `used` name expression is then given the attribute `NameExprTypeHeapUse`. This step finalizes whether a name expression will be allocated on the heap and used from heap. `Closures` represent a particular scenario in this context. Each closure, defined by a funcLitExpr that captures variables, is associated with a HeapCaptures list. This list consists of NameExprs, which are utilized at runtime to obtain the actual variable values for each iteration. Correspondingly, within the funcLitExpr block, a list of placeholder values are defined. These placeholders are populated during the doOpFuncLit phase and subsequently utilized in the `doOpCall` to ensure that each iteration uses the correct data. - **Phase 5: `findLoopUses2`**: Convert non-loop uses of loop-defined names to `NameExprTypeHeapUse`. Also, demote `NameExprTypeHeapDefine` back to `NameExprTypeDefine` if no actual usage is found. Also , as the last phase, attributes no longer needed will be cleaned up after this phase. **Runtime Stage**: 1. **Variable Allocation**: - Modify the runtime so that encountering a `NameExprTypeHeapDefine` triggers the allocation of a new `heapItemValue` for it, which will be used by any `NameExprTypeHeapUse`. 2. **Function Literal Handling**: - During the execution of `doOpFuncLit`, retrieve the `HeapCapture` values (previously allocated heap item values) and fill in the placeholder values within the `funcLitExpr` block. - When invoking the function (`doOpCall`), the `placeHolder` values(fv.Captures) are used to update the execution context, ensuring accurate and consistent results across iterations. --------- Co-authored-by: ltzMaxwell Co-authored-by: Morgan --- .../gno_test/test_with-native-fallback.txtar | 2 +- .../gno/testdata/gno_test/unknow_lib.txtar | 4 +- gnovm/pkg/gnolang/debugger.go | 14 +- gnovm/pkg/gnolang/debugger_test.go | 2 +- gnovm/pkg/gnolang/go2gno.go | 6 +- gnovm/pkg/gnolang/kind_string.go | 9 +- gnovm/pkg/gnolang/machine.go | 30 +- gnovm/pkg/gnolang/nodes.go | 120 ++- gnovm/pkg/gnolang/nodes_string.go | 21 +- gnovm/pkg/gnolang/op_assign.go | 2 +- gnovm/pkg/gnolang/op_call.go | 22 + gnovm/pkg/gnolang/op_decl.go | 4 +- gnovm/pkg/gnolang/op_eval.go | 2 +- gnovm/pkg/gnolang/op_exec.go | 26 +- gnovm/pkg/gnolang/op_expressions.go | 22 +- gnovm/pkg/gnolang/preprocess.go | 789 ++++++++++++++---- gnovm/pkg/gnolang/realm.go | 4 + gnovm/pkg/gnolang/store.go | 2 +- gnovm/pkg/gnolang/transcribe.go | 15 + gnovm/pkg/gnolang/transfield_string.go | 120 +-- gnovm/pkg/gnolang/type_check.go | 30 +- gnovm/pkg/gnolang/types.go | 39 +- gnovm/pkg/gnolang/values.go | 83 +- gnovm/tests/file.go | 59 +- .../more/realm_compositelit_filetest.gno | 6 +- gnovm/tests/files/heap_alloc_defer.gno | 37 + gnovm/tests/files/heap_alloc_defer2.gno | 28 + gnovm/tests/files/heap_alloc_forloop1.gno | 31 + gnovm/tests/files/heap_alloc_forloop1a.gno | 39 + gnovm/tests/files/heap_alloc_forloop1b.gno | 37 + gnovm/tests/files/heap_alloc_forloop2.gno | 33 + gnovm/tests/files/heap_alloc_forloop2a.gno | 34 + gnovm/tests/files/heap_alloc_forloop3.gno | 33 + gnovm/tests/files/heap_alloc_forloop3a.gno | 38 + gnovm/tests/files/heap_alloc_forloop4.gno | 31 + gnovm/tests/files/heap_alloc_forloop5.gno | 32 + gnovm/tests/files/heap_alloc_forloop5a.gno | 33 + gnovm/tests/files/heap_alloc_forloop6.gno | 25 + gnovm/tests/files/heap_alloc_forloop6a.gno | 26 + gnovm/tests/files/heap_alloc_forloop6b.gno | 25 + gnovm/tests/files/heap_alloc_forloop6c.gno | 23 + gnovm/tests/files/heap_alloc_forloop6f.gno | 26 + gnovm/tests/files/heap_alloc_forloop6g.gno | 27 + gnovm/tests/files/heap_alloc_forloop6h.gno | 33 + gnovm/tests/files/heap_alloc_forloop6h0.gno | 27 + gnovm/tests/files/heap_alloc_forloop6i.gno | 34 + gnovm/tests/files/heap_alloc_forloop7.gno | 28 + gnovm/tests/files/heap_alloc_forloop7a.gno | 26 + gnovm/tests/files/heap_alloc_forloop8.gno | 25 + gnovm/tests/files/heap_alloc_forloop8a.gno | 26 + gnovm/tests/files/heap_alloc_forloop8b.gno | 28 + gnovm/tests/files/heap_alloc_forloop8c.gno | 30 + gnovm/tests/files/heap_alloc_forloop9.gno | 42 + gnovm/tests/files/heap_alloc_forloop9_1.gno | 25 + gnovm/tests/files/heap_alloc_forloop9_2.gno | 36 + gnovm/tests/files/heap_alloc_forloop9b.gno | 28 + gnovm/tests/files/heap_alloc_gotoloop0.gno | 28 + gnovm/tests/files/heap_alloc_gotoloop1.gno | 30 + gnovm/tests/files/heap_alloc_gotoloop2.gno | 37 + gnovm/tests/files/heap_alloc_gotoloop3.gno | 34 + gnovm/tests/files/heap_alloc_gotoloop4.gno | 34 + gnovm/tests/files/heap_alloc_gotoloop5.gno | 39 + gnovm/tests/files/heap_alloc_gotoloop6.gno | 39 + gnovm/tests/files/heap_alloc_gotoloop7.gno | 48 ++ gnovm/tests/files/heap_alloc_gotoloop8.gno | 37 + gnovm/tests/files/heap_alloc_gotoloop9.gno | 35 + gnovm/tests/files/heap_alloc_gotoloop9_10.gno | 64 ++ gnovm/tests/files/heap_alloc_gotoloop9_11.gno | 29 + gnovm/tests/files/heap_alloc_gotoloop9_12.gno | 56 ++ gnovm/tests/files/heap_alloc_gotoloop9_13.gno | 41 + gnovm/tests/files/heap_alloc_gotoloop9_14.gno | 43 + gnovm/tests/files/heap_alloc_gotoloop9_15.gno | 48 ++ .../tests/files/heap_alloc_gotoloop9_15a.gno | 46 + gnovm/tests/files/heap_alloc_gotoloop9_16.gno | 58 ++ gnovm/tests/files/heap_alloc_gotoloop9_17.gno | 58 ++ gnovm/tests/files/heap_alloc_gotoloop9_18.gno | 30 + gnovm/tests/files/heap_alloc_gotoloop9_19.gno | 30 + gnovm/tests/files/heap_alloc_gotoloop9_20.gno | 32 + gnovm/tests/files/heap_alloc_gotoloop9_21.gno | 31 + .../tests/files/heap_alloc_gotoloop9_21a.gno | 33 + .../tests/files/heap_alloc_gotoloop9_21b.gno | 34 + gnovm/tests/files/heap_alloc_gotoloop9_22.gno | 33 + gnovm/tests/files/heap_alloc_range1.gno | 30 + gnovm/tests/files/heap_alloc_range2.gno | 30 + gnovm/tests/files/heap_alloc_range3.gno | 23 + gnovm/tests/files/heap_alloc_range4.gno | 24 + gnovm/tests/files/heap_alloc_range4a.gno | 26 + gnovm/tests/files/heap_alloc_range4a1.gno | 22 + gnovm/tests/files/heap_alloc_range4a2.gno | 32 + gnovm/tests/files/heap_alloc_range4b.gno | 26 + gnovm/tests/files/heap_alloc_range4b1.gno | 25 + gnovm/tests/files/import6.gno | 2 +- gnovm/tests/files/recursive1.gno | 2 +- gnovm/tests/files/recursive1c.gno | 2 +- gnovm/tests/files/recursive1d.gno | 2 +- gnovm/tests/files/recursive1f.gno | 2 +- gnovm/tests/files/recursive2.gno | 2 +- gnovm/tests/files/recursive2c.gno | 2 +- gnovm/tests/files/recursive4a.gno | 2 +- gnovm/tests/files/recursive5.gno | 2 +- gnovm/tests/files/recursive6a.gno | 2 +- gnovm/tests/files/recursive7a.gno | 2 +- gnovm/tests/files/recursive8.gno | 2 +- gnovm/tests/files/recursive9.gno | 2 +- gnovm/tests/files/recursive9a.gno | 2 +- gnovm/tests/files/recursive9b.gno | 2 +- gnovm/tests/files/recursive9c.gno | 2 +- gnovm/tests/files/recursive9d.gno | 2 +- gnovm/tests/files/switch13.gno | 2 +- gnovm/tests/files/types/assign_literal11.gno | 2 +- gnovm/tests/files/types/assign_literal3.gno | 2 +- gnovm/tests/files/types/assign_nil.gno | 2 +- gnovm/tests/files/types/assign_nil2.gno | 2 +- gnovm/tests/files/var18.gno | 2 +- gnovm/tests/files/var19.gno | 5 +- gnovm/tests/files/var22.gno | 2 +- 116 files changed, 3343 insertions(+), 354 deletions(-) create mode 100644 gnovm/tests/files/heap_alloc_defer.gno create mode 100644 gnovm/tests/files/heap_alloc_defer2.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop1.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop1a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop1b.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop2.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop2a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop3.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop3a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop4.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop5.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop5a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6b.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6c.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6f.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6g.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6h.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6h0.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop6i.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop7.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop7a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop8.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop8a.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop8b.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop8c.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop9.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop9_1.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop9_2.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop9b.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop0.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop1.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop2.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop3.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop4.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop5.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop6.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop7.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop8.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_10.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_11.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_12.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_13.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_14.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_15.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_15a.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_16.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_17.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_18.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_19.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_20.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_21.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_21a.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_21b.gno create mode 100644 gnovm/tests/files/heap_alloc_gotoloop9_22.gno create mode 100644 gnovm/tests/files/heap_alloc_range1.gno create mode 100644 gnovm/tests/files/heap_alloc_range2.gno create mode 100644 gnovm/tests/files/heap_alloc_range3.gno create mode 100644 gnovm/tests/files/heap_alloc_range4.gno create mode 100644 gnovm/tests/files/heap_alloc_range4a.gno create mode 100644 gnovm/tests/files/heap_alloc_range4a1.gno create mode 100644 gnovm/tests/files/heap_alloc_range4a2.gno create mode 100644 gnovm/tests/files/heap_alloc_range4b.gno create mode 100644 gnovm/tests/files/heap_alloc_range4b1.gno diff --git a/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar b/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar index 0954d1dd932..6099788a9a1 100644 --- a/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar @@ -4,7 +4,7 @@ ! stdout .+ stderr 'panic: unknown import path net \[recovered\]' -stderr ' panic: gno.land/r/\w{8}/contract.gno:3:1: unknown import path net' +stderr ' panic: gno.land/r/\w{8}/contract.gno:3:8: unknown import path net' gno test -v --with-native-fallback . diff --git a/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar b/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar index 15125f695f5..37ef68f3d91 100644 --- a/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar @@ -4,13 +4,13 @@ ! stdout .+ stderr 'panic: unknown import path foobarbaz \[recovered\]' -stderr ' panic: gno.land/r/\w{8}/contract.gno:3:1: unknown import path foobarbaz' +stderr ' panic: gno.land/r/\w{8}/contract.gno:3:8: unknown import path foobarbaz' ! gno test -v --with-native-fallback . ! stdout .+ stderr 'panic: unknown import path foobarbaz \[recovered\]' -stderr ' panic: gno.land/r/\w{8}/contract.gno:3:1: unknown import path foobarbaz' +stderr ' panic: gno.land/r/\w{8}/contract.gno:3:8: unknown import path foobarbaz' -- contract.gno -- package contract diff --git a/gnovm/pkg/gnolang/debugger.go b/gnovm/pkg/gnolang/debugger.go index 839b6a691de..f047a176af7 100644 --- a/gnovm/pkg/gnolang/debugger.go +++ b/gnovm/pkg/gnolang/debugger.go @@ -257,8 +257,10 @@ func debugUpdateLocation(m *Machine) { for i := nx - 1; i >= 0; i-- { expr := m.Exprs[i] if l := expr.GetLine(); l > 0 { - m.Debugger.loc.Line = l - m.Debugger.loc.Column = expr.GetColumn() + if col := expr.GetColumn(); col > 0 { + m.Debugger.loc.Line = l + m.Debugger.loc.Column = expr.GetColumn() + } return } } @@ -266,8 +268,10 @@ func debugUpdateLocation(m *Machine) { if len(m.Stmts) > 0 { if stmt := m.PeekStmt1(); stmt != nil { if l := stmt.GetLine(); l > 0 { - m.Debugger.loc.Line = l - m.Debugger.loc.Column = stmt.GetColumn() + if col := stmt.GetColumn(); col > 0 { + m.Debugger.loc.Line = l + m.Debugger.loc.Column = stmt.GetColumn() + } return } } @@ -648,7 +652,7 @@ func debugEvalExpr(m *Machine, node ast.Node) (tv TypedValue, err error) { return tv, fmt.Errorf("invalid selector: %s", n.Sel.Name) } for _, vp := range tr { - x = x.GetPointerTo(m.Alloc, m.Store, vp).Deref() + x = x.GetPointerToFromTV(m.Alloc, m.Store, vp).Deref() } return x, nil case *ast.IndexExpr: diff --git a/gnovm/pkg/gnolang/debugger_test.go b/gnovm/pkg/gnolang/debugger_test.go index fe059ba9f56..44786257d67 100644 --- a/gnovm/pkg/gnolang/debugger_test.go +++ b/gnovm/pkg/gnolang/debugger_test.go @@ -131,7 +131,7 @@ func TestDebug(t *testing.T) { {in: "p \"xxxx\"\n", out: `("xxxx" string)`}, {in: "si\n", out: "sample.gno:14"}, {in: "s\ns\n", out: `=> 14: var global = "test"`}, - {in: "s\n\n", out: "=> 33: num := 5"}, + {in: "s\n\n\n", out: "=> 33: num := 5"}, {in: "foo", out: "command not available: foo"}, {in: "\n\n", out: "dbg> "}, {in: "#\n", out: "dbg> "}, diff --git a/gnovm/pkg/gnolang/go2gno.go b/gnovm/pkg/gnolang/go2gno.go index efdfecf0289..6bde6fb5271 100644 --- a/gnovm/pkg/gnolang/go2gno.go +++ b/gnovm/pkg/gnolang/go2gno.go @@ -754,11 +754,13 @@ func toDecls(fs *token.FileSet, gd *ast.GenDecl) (ds Decls) { name := toName(s.Name) tipe := toExpr(fs, s.Type) alias := s.Assign != 0 - ds = append(ds, &TypeDecl{ + td := &TypeDecl{ NameExpr: NameExpr{Name: name}, Type: tipe, IsAlias: alias, - }) + } + setLoc(fs, s.Pos(), td) + ds = append(ds, td) case *ast.ValueSpec: if gd.Tok == token.CONST { var names []NameExpr diff --git a/gnovm/pkg/gnolang/kind_string.go b/gnovm/pkg/gnolang/kind_string.go index cbe6bfa8e33..12e95829b20 100644 --- a/gnovm/pkg/gnolang/kind_string.go +++ b/gnovm/pkg/gnolang/kind_string.go @@ -36,13 +36,14 @@ func _() { _ = x[MapKind-25] _ = x[TypeKind-26] _ = x[BlockKind-27] - _ = x[TupleKind-28] - _ = x[RefTypeKind-29] + _ = x[HeapItemKind-28] + _ = x[TupleKind-29] + _ = x[RefTypeKind-30] } -const _Kind_name = "InvalidKindBoolKindStringKindIntKindInt8KindInt16KindInt32KindInt64KindUintKindUint8KindUint16KindUint32KindUint64KindFloat32KindFloat64KindBigintKindBigdecKindArrayKindSliceKindPointerKindStructKindPackageKindInterfaceKindChanKindFuncKindMapKindTypeKindBlockKindTupleKindRefTypeKind" +const _Kind_name = "InvalidKindBoolKindStringKindIntKindInt8KindInt16KindInt32KindInt64KindUintKindUint8KindUint16KindUint32KindUint64KindFloat32KindFloat64KindBigintKindBigdecKindArrayKindSliceKindPointerKindStructKindPackageKindInterfaceKindChanKindFuncKindMapKindTypeKindBlockKindHeapItemKindTupleKindRefTypeKind" -var _Kind_index = [...]uint16{0, 11, 19, 29, 36, 44, 53, 62, 71, 79, 88, 98, 108, 118, 129, 140, 150, 160, 169, 178, 189, 199, 210, 223, 231, 239, 246, 254, 263, 272, 283} +var _Kind_index = [...]uint16{0, 11, 19, 29, 36, 44, 53, 62, 71, 79, 88, 98, 108, 118, 129, 140, 150, 160, 169, 178, 189, 199, 210, 223, 231, 239, 246, 254, 263, 275, 284, 295} func (i Kind) String() string { if i >= Kind(len(_Kind_index)-1) { diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index ad94f1a2b3a..1e594de945b 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -699,7 +699,7 @@ func (m *Machine) runFileDecls(fns ...*FileNode) []TypedValue { } } // if dep already in loopfindr, abort. - if hasName(dep, loopfindr) { + if slices.Contains(loopfindr, dep) { if _, ok := (*depdecl).(*FuncDecl); ok { // recursive function dependencies // are OK with func decls. @@ -2112,15 +2112,25 @@ func (m *Machine) PushForPointer(lx Expr) { func (m *Machine) PopAsPointer(lx Expr) PointerValue { switch lx := lx.(type) { case *NameExpr: - lb := m.LastBlock() - return lb.GetPointerTo(m.Store, lx.Path) + switch lx.Type { + case NameExprTypeNormal: + lb := m.LastBlock() + return lb.GetPointerTo(m.Store, lx.Path) + case NameExprTypeHeapUse: + lb := m.LastBlock() + return lb.GetPointerToHeapUse(m.Store, lx.Path) + case NameExprTypeHeapClosure: + panic("should not happen") + default: + panic("unexpected NameExpr in PopAsPointer") + } case *IndexExpr: iv := m.PopValue() xv := m.PopValue() return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) case *SelectorExpr: xv := m.PopValue() - return xv.GetPointerTo(m.Alloc, m.Store, lx.Path) + return xv.GetPointerToFromTV(m.Alloc, m.Store, lx.Path) case *StarExpr: ptr := m.PopValue().V.(PointerValue) return ptr @@ -2348,15 +2358,3 @@ func (m *Machine) ExceptionsStacktrace() string { return builder.String() } - -//---------------------------------------- -// utility - -func hasName(n Name, ns []Name) bool { - for _, n2 := range ns { - if n == n2 { - return true - } - } - return false -} diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index f1bd78ee646..9e7cea8fb7f 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -146,11 +146,26 @@ func (loc Location) IsZero() bool { // even after preprocessing. Temporary attributes (e.g. those // for preprocessing) are stored in .data. +type GnoAttribute string + +const ( + ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED" + ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED" + ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" + ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" + ATTR_IOTA GnoAttribute = "ATTR_IOTA" + ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONE" // XXX DELETE + ATTR_GOTOLOOP_STMT GnoAttribute = "ATTR_GOTOLOOP_STMT" // XXX delete? + ATTR_LOOP_DEFINES GnoAttribute = "ATTR_LOOP_DEFINES" // []Name defined within loops. + ATTR_LOOP_USES GnoAttribute = "ATTR_LOOP_USES" // []Name loop defines actually used. + ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" +) + type Attributes struct { Line int Column int Label Name - data map[interface{}]interface{} // not persisted + data map[GnoAttribute]interface{} // not persisted } func (attr *Attributes) GetLine() int { @@ -177,22 +192,31 @@ func (attr *Attributes) SetLabel(label Name) { attr.Label = label } -func (attr *Attributes) HasAttribute(key interface{}) bool { +func (attr *Attributes) HasAttribute(key GnoAttribute) bool { _, ok := attr.data[key] return ok } -func (attr *Attributes) GetAttribute(key interface{}) interface{} { +// GnoAttribute must not be user provided / arbitrary, +// otherwise will create potential exploits. +func (attr *Attributes) GetAttribute(key GnoAttribute) interface{} { return attr.data[key] } -func (attr *Attributes) SetAttribute(key interface{}, value interface{}) { +func (attr *Attributes) SetAttribute(key GnoAttribute, value interface{}) { if attr.data == nil { - attr.data = make(map[interface{}]interface{}) + attr.data = make(map[GnoAttribute]interface{}) } attr.data[key] = value } +func (attr *Attributes) DelAttribute(key GnoAttribute) { + if debug && attr.data == nil { + panic("should not happen, attribute is expected to be non-empty.") + } + delete(attr.data, key) +} + // ---------------------------------------- // Node @@ -206,9 +230,10 @@ type Node interface { SetColumn(int) GetLabel() Name SetLabel(Name) - HasAttribute(key interface{}) bool - GetAttribute(key interface{}) interface{} - SetAttribute(key interface{}, value interface{}) + HasAttribute(key GnoAttribute) bool + GetAttribute(key GnoAttribute) interface{} + SetAttribute(key GnoAttribute, value interface{}) + DelAttribute(key GnoAttribute) } // non-pointer receiver to help make immutable. @@ -368,11 +393,22 @@ var ( _ Expr = &ConstExpr{} ) +type NameExprType int + +const ( + NameExprTypeNormal NameExprType = iota // default + NameExprTypeDefine // when defining normally + NameExprTypeHeapDefine // when defining escaped name in loop + NameExprTypeHeapUse // when above used in non-define lhs/rhs + NameExprTypeHeapClosure // when closure captures name +) + type NameExpr struct { Attributes // TODO rename .Path's to .ValuePaths. Path ValuePath // set by preprocessor. Name + Type NameExprType } type NameExprs []NameExpr @@ -499,8 +535,9 @@ type KeyValueExprs []KeyValueExpr type FuncLitExpr struct { Attributes StaticBlock - Type FuncTypeExpr // function type - Body // function body + Type FuncTypeExpr // function type + Body // function body + HeapCaptures NameExprs // filled in findLoopUses1 } // The preprocessor replaces const expressions @@ -581,11 +618,15 @@ func (ftxz FieldTypeExprs) IsNamed() bool { named := false for i, ftx := range ftxz { if i == 0 { - named = ftx.Name != "" + if ftx.Name == "" || isHiddenResultVariable(string(ftx.Name)) { + named = false + } else { + named = true + } } else { if named && ftx.Name == "" { panic("[]FieldTypeExpr has inconsistent namedness (starts named)") - } else if !named && ftx.Name != "" { + } else if !named && (ftx.Name != "" || !isHiddenResultVariable(string(ftx.Name))) { panic("[]FieldTypeExpr has inconsistent namedness (starts unnamed)") } } @@ -1489,6 +1530,7 @@ type BlockNode interface { GetNumNames() uint16 GetParentNode(Store) BlockNode GetPathForName(Store, Name) ValuePath + GetBlockNodeForPath(Store, ValuePath) BlockNode GetIsConst(Store, Name) bool GetLocalIndex(Name) (uint16, bool) GetValueRef(Store, Name, bool) *TypedValue @@ -1588,6 +1630,8 @@ func (sb *StaticBlock) GetBlockNames() (ns []Name) { } // Implements BlockNode. +// NOTE: Extern names may also be local, if declared after usage as an extern +// (thus shadowing the extern name). func (sb *StaticBlock) GetExternNames() (ns []Name) { return sb.Externs // copy? } @@ -1629,6 +1673,9 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath { } // Register as extern. // NOTE: uverse names are externs too. + // NOTE: externs may also be shadowed later in the block. Thus, usages + // before the declaration will have depth > 1; following it, depth == 1, + // matching the two different identifiers they refer to. if !isFile(sb.GetSource(store)) { sb.GetStaticBlock().addExternName(n) } @@ -1657,6 +1704,21 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath { panic(fmt.Sprintf("name %s not declared", n)) } +// Get the containing block node for node with path relative to this containing block. +func (sb *StaticBlock) GetBlockNodeForPath(store Store, path ValuePath) BlockNode { + if path.Type != VPBlock { + panic("expected block type value path but got " + path.Type.String()) + } + + // NOTE: path.Depth == 1 means it's in bn. + bn := sb.GetSource(store) + for i := 1; i < int(path.Depth); i++ { + bn = bn.GetParentNode(store) + } + + return bn +} + // Returns whether a name defined here in in ancestry is a const. // This is not the same as whether a name's static type is // untyped -- as in c := a == b, a name may be an untyped non-const. @@ -1713,21 +1775,12 @@ func (sb *StaticBlock) GetStaticTypeOf(store Store, n Name) Type { // Implements BlockNode. func (sb *StaticBlock) GetStaticTypeOfAt(store Store, path ValuePath) Type { if debug { - if path.Type != VPBlock { - panic("should not happen") - } if path.Depth == 0 { panic("should not happen") } } - for { - if path.Depth == 1 { - return sb.Types[path.Index] - } else { - sb = sb.GetParentNode(store).GetStaticBlock() - path.Depth -= 1 - } - } + bn := sb.GetBlockNodeForPath(store, path) + return bn.GetStaticBlock().Types[path.Index] } // Implements BlockNode. @@ -2115,18 +2168,6 @@ func (x *BasicLitExpr) GetInt() int { return i } -type GnoAttribute string - -const ( - ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED" - ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED" - ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" - ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" - ATTR_IOTA GnoAttribute = "ATTR_IOTA" - ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED" - ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" -) - var rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]+$`) // TODO: consider length restrictions. @@ -2136,3 +2177,12 @@ func validatePkgName(name string) { panic(fmt.Sprintf("cannot create package with invalid name %q", name)) } } + +const hiddenResultVariable = ".res_" + +func isHiddenResultVariable(name string) bool { + if strings.HasPrefix(name, hiddenResultVariable) { + return true + } + return false +} diff --git a/gnovm/pkg/gnolang/nodes_string.go b/gnovm/pkg/gnolang/nodes_string.go index 547ad83294d..e16e2f182a5 100644 --- a/gnovm/pkg/gnolang/nodes_string.go +++ b/gnovm/pkg/gnolang/nodes_string.go @@ -96,7 +96,20 @@ func (vp ValuePath) String() string { } func (x NameExpr) String() string { - return fmt.Sprintf("%s<%s>", x.Name, x.Path.String()) + switch x.Type { + case NameExprTypeNormal: + return fmt.Sprintf("%s<%s>", x.Name, x.Path.String()) + case NameExprTypeDefine: + return fmt.Sprintf("%s", x.Name, x.Path.String()) + case NameExprTypeHeapDefine: + return fmt.Sprintf("%s", x.Name, x.Path.String()) + case NameExprTypeHeapUse: + return fmt.Sprintf("%s<~%s>", x.Name, x.Path.String()) + case NameExprTypeHeapClosure: + return fmt.Sprintf("%s<()~%s>", x.Name, x.Path.String()) + default: + panic("unexpected NameExpr type") + } } func (x BasicLitExpr) String() string { @@ -172,7 +185,11 @@ func (x CompositeLitExpr) String() string { } func (x FuncLitExpr) String() string { - return fmt.Sprintf("func %s{ %s }", x.Type, x.Body.String()) + heapCaptures := "" + if len(x.HeapCaptures) > 0 { + heapCaptures = "<" + x.HeapCaptures.String() + ">" + } + return fmt.Sprintf("func %s{ %s }%s", x.Type, x.Body.String(), heapCaptures) } func (x KeyValueExpr) String() string { diff --git a/gnovm/pkg/gnolang/op_assign.go b/gnovm/pkg/gnolang/op_assign.go index eb67ffcc351..8caacbfd1e6 100644 --- a/gnovm/pkg/gnolang/op_assign.go +++ b/gnovm/pkg/gnolang/op_assign.go @@ -11,7 +11,7 @@ func (m *Machine) doOpDefine() { // Get name and value of i'th term. nx := s.Lhs[i].(*NameExpr) // Finally, define (or assign if loop block). - ptr := lb.GetPointerTo(m.Store, nx.Path) + ptr := lb.GetPointerToMaybeHeapDefine(m.Store, nx) // XXX HACK (until value persistence impl'd) if m.ReadOnly { if oo, ok := ptr.Base.(Object); ok { diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 510c308a86a..ba5b7507cff 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -62,6 +62,18 @@ func (m *Machine) doOpCall() { // Create new block scope. clo := fr.Func.GetClosure(m.Store) b := m.Alloc.NewBlock(fr.Func.GetSource(m.Store), clo) + + // Copy *FuncValue.Captures into block + // NOTE: addHeapCapture in preprocess ensures order. + if len(fv.Captures) != 0 { + if len(fv.Captures) > len(b.Values) { + panic("should not happen, length of captured variables must not exceed the number of values") + } + for i := 0; i < len(fv.Captures); i++ { + b.Values[len(b.Values)-len(fv.Captures)+i] = fv.Captures[i].Copy(m.Alloc) + } + } + m.PushBlock(b) if fv.nativeBody == nil && fv.NativePkg != "" { // native function, unmarshaled so doesn't have nativeBody yet @@ -83,6 +95,7 @@ func (m *Machine) doOpCall() { // Initialize return variables with default value. numParams := len(ft.Params) for i, rt := range ft.Results { + // results/parameters never are heap use/closure. ptr := b.GetPointerToInt(nil, numParams+i) dtv := defaultTypedValue(m.Alloc, rt.Type) ptr.Assign2(m.Alloc, nil, nil, dtv, false) @@ -292,6 +305,15 @@ func (m *Machine) doOpReturnCallDefers() { // Create new block scope for defer. clo := dfr.Func.GetClosure(m.Store) b := m.Alloc.NewBlock(fv.GetSource(m.Store), clo) + // copy values from captures + if len(fv.Captures) != 0 { + if len(fv.Captures) > len(b.Values) { + panic("should not happen, length of captured variables must not exceed the number of values") + } + for i := 0; i < len(fv.Captures); i++ { + b.Values[len(b.Values)-len(fv.Captures)+i] = fv.Captures[i].Copy(m.Alloc) + } + } m.PushBlock(b) if fv.nativeBody == nil { fbody := fv.GetBodyFromSource(m.Store) diff --git a/gnovm/pkg/gnolang/op_decl.go b/gnovm/pkg/gnolang/op_decl.go index 2c20c43ae2f..c9c04ccf76d 100644 --- a/gnovm/pkg/gnolang/op_decl.go +++ b/gnovm/pkg/gnolang/op_decl.go @@ -58,8 +58,8 @@ func (m *Machine) doOpValueDecl() { } else if isUntyped(tv.T) { ConvertUntypedTo(&tv, nil) } - nx := s.NameExprs[i] - ptr := lb.GetPointerTo(m.Store, nx.Path) + nx := &s.NameExprs[i] + ptr := lb.GetPointerToMaybeHeapDefine(m.Store, nx) ptr.Assign2(m.Alloc, m.Store, m.Realm, tv, false) } } diff --git a/gnovm/pkg/gnolang/op_eval.go b/gnovm/pkg/gnolang/op_eval.go index 701615fff13..1beba1d6e3f 100644 --- a/gnovm/pkg/gnolang/op_eval.go +++ b/gnovm/pkg/gnolang/op_eval.go @@ -36,7 +36,7 @@ func (m *Machine) doOpEval() { // Get value from scope. lb := m.LastBlock() // Push value, done. - ptr := lb.GetPointerTo(m.Store, nx.Path) + ptr := lb.GetPointerToMaybeHeapUse(m.Store, nx) m.PushValue(ptr.Deref()) return } diff --git a/gnovm/pkg/gnolang/op_exec.go b/gnovm/pkg/gnolang/op_exec.go index c7e8ffd600c..a61349b0806 100644 --- a/gnovm/pkg/gnolang/op_exec.go +++ b/gnovm/pkg/gnolang/op_exec.go @@ -171,8 +171,8 @@ func (m *Machine) doOpExec(op Op) { case ASSIGN: m.PopAsPointer(bs.Key).Assign2(m.Alloc, m.Store, m.Realm, iv, false) case DEFINE: - knxp := bs.Key.(*NameExpr).Path - ptr := m.LastBlock().GetPointerTo(m.Store, knxp) + knx := bs.Key.(*NameExpr) + ptr := m.LastBlock().GetPointerToMaybeHeapDefine(m.Store, knx) ptr.TV.Assign(m.Alloc, iv, false) default: panic("should not happen") @@ -186,8 +186,8 @@ func (m *Machine) doOpExec(op Op) { case ASSIGN: m.PopAsPointer(bs.Value).Assign2(m.Alloc, m.Store, m.Realm, ev, false) case DEFINE: - vnxp := bs.Value.(*NameExpr).Path - ptr := m.LastBlock().GetPointerTo(m.Store, vnxp) + vnx := bs.Value.(*NameExpr) + ptr := m.LastBlock().GetPointerToMaybeHeapDefine(m.Store, vnx) ptr.TV.Assign(m.Alloc, ev, false) default: panic("should not happen") @@ -267,8 +267,8 @@ func (m *Machine) doOpExec(op Op) { case ASSIGN: m.PopAsPointer(bs.Key).Assign2(m.Alloc, m.Store, m.Realm, iv, false) case DEFINE: - knxp := bs.Key.(*NameExpr).Path - ptr := m.LastBlock().GetPointerTo(m.Store, knxp) + knx := bs.Key.(*NameExpr) + ptr := m.LastBlock().GetPointerToMaybeHeapDefine(m.Store, knx) ptr.TV.Assign(m.Alloc, iv, false) default: panic("should not happen") @@ -280,8 +280,8 @@ func (m *Machine) doOpExec(op Op) { case ASSIGN: m.PopAsPointer(bs.Value).Assign2(m.Alloc, m.Store, m.Realm, ev, false) case DEFINE: - vnxp := bs.Value.(*NameExpr).Path - ptr := m.LastBlock().GetPointerTo(m.Store, vnxp) + vnx := bs.Value.(*NameExpr) + ptr := m.LastBlock().GetPointerToMaybeHeapDefine(m.Store, vnx) ptr.TV.Assign(m.Alloc, ev, false) default: panic("should not happen") @@ -360,8 +360,8 @@ func (m *Machine) doOpExec(op Op) { case ASSIGN: m.PopAsPointer(bs.Key).Assign2(m.Alloc, m.Store, m.Realm, kv, false) case DEFINE: - knxp := bs.Key.(*NameExpr).Path - ptr := m.LastBlock().GetPointerTo(m.Store, knxp) + knx := bs.Key.(*NameExpr) + ptr := m.LastBlock().GetPointerToMaybeHeapDefine(m.Store, knx) ptr.TV.Assign(m.Alloc, kv, false) default: panic("should not happen") @@ -373,8 +373,8 @@ func (m *Machine) doOpExec(op Op) { case ASSIGN: m.PopAsPointer(bs.Value).Assign2(m.Alloc, m.Store, m.Realm, vv, false) case DEFINE: - vnxp := bs.Value.(*NameExpr).Path - ptr := m.LastBlock().GetPointerTo(m.Store, vnxp) + vnx := bs.Value.(*NameExpr) + ptr := m.LastBlock().GetPointerToMaybeHeapDefine(m.Store, vnx) ptr.TV.Assign(m.Alloc, vv, false) default: panic("should not happen") @@ -884,6 +884,8 @@ func (m *Machine) doOpTypeSwitch() { // NOTE: assumes the var is first in block. vp := NewValuePath( VPBlock, 1, 0, ss.VarName) + // NOTE: GetPointerToMaybeHeapDefine not needed, + // because this type is in new type switch clause block. ptr := b.GetPointerTo(m.Store, vp) ptr.TV.Assign(m.Alloc, *xv, false) } diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 8ff0b5bd538..a1d677ca878 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -78,7 +78,7 @@ func (m *Machine) doOpIndex2() { func (m *Machine) doOpSelector() { sx := m.PopExpr().(*SelectorExpr) xv := m.PeekValue(1) - res := xv.GetPointerTo(m.Alloc, m.Store, sx.Path).Deref() + res := xv.GetPointerToFromTV(m.Alloc, m.Store, sx.Path).Deref() if debug { m.Printf("-v[S] %v\n", xv) m.Printf("+v[S] %v\n", res) @@ -758,6 +758,25 @@ func (m *Machine) doOpFuncLit() { ft := m.PopValue().V.(TypeValue).Type.(*FuncType) lb := m.LastBlock() m.Alloc.AllocateFunc() + + // First copy closure captured heap values + // to *FuncValue. Later during doOpCall a block + // will be created that copies these values for + // every invocation of the function. + captures := []TypedValue(nil) + for _, nx := range x.HeapCaptures { + ptr := lb.GetPointerTo(m.Store, nx.Path) + // check that ptr.TV is a heap item value. + // it must be in the form of: + // {T:heapItemType{},V:HeapItemValue{...}} + if _, ok := ptr.TV.T.(heapItemType); !ok { + panic("should not happen, should be heapItemType") + } + if _, ok := ptr.TV.V.(*HeapItemValue); !ok { + panic("should not happen, should be heapItemValue") + } + captures = append(captures, *ptr.TV) + } m.PushValue(TypedValue{ T: ft, V: &FuncValue{ @@ -766,6 +785,7 @@ func (m *Machine) doOpFuncLit() { Source: x, Name: "", Closure: lb, + Captures: captures, PkgPath: m.Package.PkgPath, body: x.Body, nativeBody: nil, diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 757cbbae317..e1dc3671333 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2,8 +2,10 @@ package gnolang import ( "fmt" + "math" "math/big" "reflect" + "slices" "strings" "sync/atomic" @@ -23,7 +25,8 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { // This will also reserve names on BlockNode.StaticBlock by // calling StaticBlock.Predefine(). for _, fn := range fset.Files { - SetNodeLocations(pn.PkgPath, string(fn.Name), fn) + setNodeLines(fn) + setNodeLocations(pn.PkgPath, string(fn.Name), fn) initStaticBlocks(store, pn, fn) } // NOTE: The calls to .Predefine() above is more of a name reservation, @@ -92,7 +95,7 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } } } - // Finally, predefine other decls and + // Then, predefine other decls and // preprocess ValueDecls.. for _, fn := range fset.Files { for i := 0; i < len(fn.Decls); i++ { @@ -143,32 +146,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // iterate over all nodes recursively. _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { - defer func() { - if r := recover(); r != nil { - // before re-throwing the error, append location information to message. - loc := last.GetLocation() - if nline := n.GetLine(); nline > 0 { - loc.Line = nline - } - - var err error - rerr, ok := r.(error) - if ok { - // NOTE: gotuna/gorilla expects error exceptions. - err = errors.Wrap(rerr, loc.String()) - } else { - // NOTE: gotuna/gorilla expects error exceptions. - err = fmt.Errorf("%s: %v", loc.String(), r) - } - - // Re-throw the error after wrapping it with the preprocessing stack information. - panic(&PreprocessError{ - err: err, - stack: stack, - }) - } - }() - + defer doRecover(stack, n) if debug { debug.Printf("initStaticBlocks %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) } @@ -181,45 +159,57 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { if n.Op == DEFINE { var defined bool for _, lx := range n.Lhs { - ln := lx.(*NameExpr).Name + nx := lx.(*NameExpr) + ln := nx.Name if ln == blankIdentifier { continue } - last.Predefine(false, ln) - defined = true + if !isLocallyDefined2(last, ln) { + // if loop extern, will change to + // NameExprTypeHeapDefine later. + nx.Type = NameExprTypeDefine + last.Predefine(false, ln) + defined = true + } } if !defined { panic(fmt.Sprintf("nothing defined in assignment %s", n.String())) } } case *ImportDecl: - name := n.Name - if name == "." { + nx := &n.NameExpr + nn := nx.Name + if nn == "." { panic("dot imports not allowed in gno") } - if name == "" { // use default + if nn == "" { // use default pv := store.GetPackage(n.PkgPath, true) if pv == nil { panic(fmt.Sprintf( "unknown import path %s", n.PkgPath)) } - name = pv.PkgName + nn = pv.PkgName } - if name != blankIdentifier { - last.Predefine(false, name) + if nn != blankIdentifier { + nx.Type = NameExprTypeDefine + last.Predefine(false, nn) } case *ValueDecl: last2 := skipFile(last) for i := 0; i < len(n.NameExprs); i++ { nx := &n.NameExprs[i] - if nx.Name == blankIdentifier { + nn := nx.Name + if nn == blankIdentifier { continue } - last2.Predefine(n.Const, nx.Name) + nx.Type = NameExprTypeDefine + last2.Predefine(n.Const, nn) } case *TypeDecl: last2 := skipFile(last) + nx := &n.NameExpr + nx.Type = NameExprTypeDefine last2.Predefine(false, n.Name) case *FuncDecl: if n.IsMethod { @@ -238,7 +228,8 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { dname := Name(fmt.Sprintf("init.%d", idx)) n.Name = dname } - + nx := &n.NameExpr + nx.Type = NameExprTypeDefine pkg.Predefine(false, n.Name) } case *FuncTypeExpr: @@ -256,7 +247,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { if r.Name == blankIdentifier { // create a hidden var with leading dot. // NOTE: document somewhere. - rn := fmt.Sprintf(".res_%d", i) + rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) r.Name = Name(rn) } } @@ -265,15 +256,9 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // ---------------------------------------- case TRANS_BLOCK: + pushInitBlock(n.(BlockNode), &last, &stack) switch n := n.(type) { - case *BlockStmt: - pushInitBlock(n, &last, &stack) - case *ForStmt: - pushInitBlock(n, &last, &stack) - case *IfStmt: - pushInitBlock(n, &last, &stack) case *IfCaseStmt: - pushInitRealBlock(n, &last, &stack) // parent if statement. ifs := ns[len(ns)-1].(*IfStmt) // anything declared in ifs are copied. @@ -281,17 +266,27 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { last.Predefine(false, n) } case *RangeStmt: - pushInitBlock(n, &last, &stack) if n.Op == DEFINE { if n.Key != nil { - last.Predefine(false, n.Key.(*NameExpr).Name) + nx := n.Key.(*NameExpr) + if nx.Name != blankIdentifier { + // XXX, this should be uncommented when fully + // support Go1.22 loopvar, to make it consistent + // with for i := 0; i < 10; i++ {...}. + // nx.Type = NameExprTypeDefine + + last.Predefine(false, nx.Name) + } } if n.Value != nil { - last.Predefine(false, n.Value.(*NameExpr).Name) + nx := n.Value.(*NameExpr) + if nx.Name != blankIdentifier { + // nx.Type = NameExprTypeDefine // XXX,ditto + last.Predefine(false, nx.Name) + } } } case *FuncLitExpr: - pushInitBlock(n, &last, &stack) for _, p := range n.Type.Params { last.Predefine(false, p.Name) } @@ -300,10 +295,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { last.Predefine(false, rf.Name) } } - case *SelectCaseStmt: - pushInitBlock(n, &last, &stack) case *SwitchStmt: - pushInitBlock(n, &last, &stack) if n.VarName != "" { // NOTE: this defines for default clauses too, // see comment on block copying @ @@ -311,7 +303,6 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { last.Predefine(false, n.VarName) } case *SwitchClauseStmt: - pushInitRealBlock(n, &last, &stack) // parent switch statement. ss := ns[len(ns)-1].(*SwitchStmt) // anything declared in ss are copied, @@ -329,7 +320,6 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { } } case *FuncDecl: - pushInitBlock(n, &last, &stack) if n.IsMethod { n.Predefine(false, n.Recv.Name) } @@ -339,23 +329,24 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { } n.Predefine(false, pte.Name) } - for _, rte := range n.Type.Results { - if rte.Name != "" { - n.Predefine(false, rte.Name) + for i, rte := range n.Type.Results { + if rte.Name == "" { + rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) + rte.Name = Name(rn) } + n.Predefine(false, rte.Name) } - case *FileNode: - pushInitBlock(n, &last, &stack) - default: - panic("should not happen") } return n, TRANS_CONTINUE // ---------------------------------------- case TRANS_LEAVE: - // finalization. - if _, ok := n.(BlockNode); ok { - // Pop block. + // Pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + switch n.(type) { + case BlockNode: stack = stack[:len(stack)-1] last = stack[len(stack)-1] } @@ -365,6 +356,34 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { }) } +func doRecover(stack []BlockNode, n Node) { + if r := recover(); r != nil { + // before re-throwing the error, append location information to message. + last := stack[len(stack)-1] + loc := last.GetLocation() + if nline := n.GetLine(); nline > 0 { + loc.Line = nline + loc.Column = n.GetColumn() + } + + var err error + rerr, ok := r.(error) + if ok { + // NOTE: gotuna/gorilla expects error exceptions. + err = errors.Wrap(rerr, loc.String()) + } else { + // NOTE: gotuna/gorilla expects error exceptions. + err = fmt.Errorf("%s: %v", loc.String(), r) + } + + // Re-throw the error after wrapping it with the preprocessing stack information. + panic(&PreprocessError{ + err: err, + stack: stack, + }) + } +} + // This counter ensures (during testing) that certain functions // (like ConvertUntypedTo() for bigints and strings) // are only called during the preprocessing stage. @@ -390,6 +409,27 @@ var preprocessing atomic.Int32 // - Assigns BlockValuePath to NameExprs. // - TODO document what it does. func Preprocess(store Store, ctx BlockNode, n Node) Node { + // If initStaticBlocks doesn't happen here, + // it means Preprocess on blocks might fail. + // it works for now because preprocess also does pushInitBlock, + // but it's kinda weird. + // maybe consider moving initStaticBlocks here and ensure idempotency of it. + n = preprocess1(store, ctx, n) + // XXX check node lines and locations + checkNodeLinesLocations("XXXpkgPath", "XXXfileName", n) + // XXX what about the fact that preprocess1 sets the PREPROCESSED attr on all nodes? + // XXX do any of the following need the attr, or similar attrs? + // XXX well the following may be isn't idempotent, + // XXX so it is currently strange. + if bn, ok := n.(BlockNode); ok { + findGotoLoopDefines(ctx, bn) + findLoopUses1(ctx, bn) + findLoopUses2(ctx, bn) + } + return n +} + +func preprocess1(store Store, ctx BlockNode, n Node) Node { // Increment preprocessing counter while preprocessing. preprocessing.Add(1) defer preprocessing.Add(-1) @@ -403,7 +443,8 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { if fn, ok := n.(*FileNode); ok { pkgPath := ctx.(*PackageNode).PkgPath fileName := string(fn.Name) - SetNodeLocations(pkgPath, fileName, fn) + setNodeLines(fn) + setNodeLocations(pkgPath, fileName, fn) } // create stack of BlockNodes. @@ -419,32 +460,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { return n, TRANS_SKIP } - defer func() { - if r := recover(); r != nil { - // before re-throwing the error, append location information to message. - loc := last.GetLocation() - if nline := n.GetLine(); nline > 0 { - loc.Line = nline - loc.Column = n.GetColumn() - } - - var err error - rerr, ok := r.(error) - if ok { - // NOTE: gotuna/gorilla expects error exceptions. - err = errors.Wrap(rerr, loc.String()) - } else { - // NOTE: gotuna/gorilla expects error exceptions. - err = fmt.Errorf("%s: %v", loc.String(), r) - } - - // Re-throw the error after wrapping it with the preprocessing stack information. - panic(&PreprocessError{ - err: err, - stack: stack, - }) - } - }() + defer doRecover(stack, n) if debug { debug.Printf("Preprocess %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) } @@ -540,7 +556,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // TRANS_BLOCK ----------------------- case *IfCaseStmt: - pushInitRealBlockAndCopy(n, &last, &stack) + pushInitBlockAndCopy(n, &last, &stack) // parent if statement. ifs := ns[len(ns)-1].(*IfStmt) // anything declared in ifs are copied. @@ -624,7 +640,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } else { // create a hidden var with leading dot. // NOTE: document somewhere. - rn := fmt.Sprintf(".res_%d", i) + rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) last.Define(Name(rn), anyValue(rf.Type)) } } @@ -656,7 +672,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // TRANS_BLOCK ----------------------- case *SwitchClauseStmt: - pushInitRealBlockAndCopy(n, &last, &stack) + pushInitBlockAndCopy(n, &last, &stack) // parent switch statement. ss := ns[len(ns)-1].(*SwitchStmt) // anything declared in ss are copied, @@ -750,7 +766,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { last.Define(rf.Name, anyValue(rf.Type)) } else { // create a hidden var with leading dot. - rn := fmt.Sprintf(".res_%d", i) + rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) last.Define(Name(rn), anyValue(rf.Type)) } } @@ -869,15 +885,23 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // in evalStaticType(store,). n.SetAttribute(ATTR_PREPROCESSED, true) - // -There is still work to be done while leaving, but - // once the logic of that is done, we will have to - // perform additionally deferred logic that is best - // handled with orthogonal switch conditions. - // -For example, while leaving nodes w/ - // TRANS_COMPOSITE_TYPE, (regardless of whether name or - // literal), any elided type names are inserted. (This - // works because the transcriber leaves the composite - // type before entering the kv elements.) + // Defer pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + defer func() { + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + }() + + // While leaving nodes w/ TRANS_COMPOSITE_TYPE, + // (regardless of whether name or literal), any elided + // type names are inserted. (This works because the + // transcriber leaves the composite type before + // entering the kv elements.) defer func() { switch ftype { // TRANS_LEAVE (deferred)--------- @@ -963,6 +987,10 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { if ftype == TRANS_ASSIGN_LHS { as := ns[len(ns)-1].(*AssignStmt) fillNameExprPath(last, n, as.Op == DEFINE) + return n, TRANS_CONTINUE + } else if ftype == TRANS_VAR_NAME { + fillNameExprPath(last, n, true) + return n, TRANS_CONTINUE } else { fillNameExprPath(last, n, false) } @@ -1389,7 +1417,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // convert to byteslice. args1 := n.Args[1] if evalStaticTypeOf(store, last, args1).Kind() == StringKind { - bsx := constType(nil, gByteSliceType) + bsx := constType(n, gByteSliceType) args1 = Call(bsx, args1) args1 = Preprocess(nil, last, args1).(Expr) n.Args[1] = args1 @@ -1424,7 +1452,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // convert to byteslice. args1 := n.Args[1] if evalStaticTypeOf(store, last, args1).Kind() == StringKind { - bsx := constType(nil, gByteSliceType) + bsx := constType(n, gByteSliceType) args1 = Call(bsx, args1) args1 = Preprocess(nil, last, args1).(Expr) n.Args[1] = args1 @@ -2152,6 +2180,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { panic("should not happen") } + // TRANS_LEAVE ----------------------- case *IncDecStmt: xt := evalStaticTypeOf(store, last, n.X) n.AssertCompatible(xt) @@ -2479,13 +2508,6 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } // end type switch statement // END TRANS_LEAVE ----------------------- - - // finalization (during leave). - if _, ok := n.(BlockNode); ok { - // Pop block. - stack = stack[:len(stack)-1] - last = stack[len(stack)-1] - } return n, TRANS_CONTINUE } @@ -2496,6 +2518,458 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { return nn } +// Identifies NameExprTypeHeapDefines. +// Also finds GotoLoopStmts, XXX but probably remove, not needed. +func findGotoLoopDefines(ctx BlockNode, bn BlockNode) { + // create stack of BlockNodes. + var stack []BlockNode = make([]BlockNode, 0, 32) + var last BlockNode = ctx + stack = append(stack, last) + + // iterate over all nodes recursively. + _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + defer doRecover(stack, n) + + if debug { + debug.Printf("findGotoLoopDefines %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + } + + switch stage { + // ---------------------------------------- + case TRANS_ENTER: + return n, TRANS_CONTINUE + + // ---------------------------------------- + case TRANS_BLOCK: + pushInitBlock(n.(BlockNode), &last, &stack) + return n, TRANS_CONTINUE + + // ---------------------------------------- + case TRANS_LEAVE: + + // Defer pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + defer func() { + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + }() + + switch n := n.(type) { + case *ForStmt, *RangeStmt: + Transcribe(n, + func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + switch stage { + case TRANS_ENTER: + switch n := n.(type) { + case *FuncLitExpr: + // inner funcs. + return n, TRANS_SKIP + case *FuncDecl: + panic("unexpected inner func decl") + case *NameExpr: + if n.Type == NameExprTypeDefine { + n.Type = NameExprTypeHeapDefine + } + } + } + return n, TRANS_CONTINUE + }) + case *BranchStmt: + switch n.Op { + case GOTO: + bn, _, _ := findGotoLabel(last, n.Label) + // already done in Preprocess: + // n.Depth = depth + // n.BodyIndex = index + + // NOTE: we must not use line numbers + // for logic, as line numbers are not + // guaranteed (see checkNodeLinesLocations). + // Instead we rely on the transcribe order + // and keep track of whether we've seen + // the label and goto stmts respectively. + // + // DOES NOT WORK: + // gotoLine := n.GetLine() + // if labelLine >= gotoLine { + // return n, TRANS_SKIP + // } + var ( + label = n.Label + labelReached bool + origGoto = n + ) + + // Recurse and mark stmts as ATTR_GOTOLOOP_STMT. + // NOTE: ATTR_GOTOLOOP_STMT is not used. + Transcribe(bn, + func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + switch stage { + case TRANS_ENTER: + // Check to see if label reached. + if _, ok := n.(Stmt); ok { + // XXX HasLabel + if n.GetLabel() == label { + labelReached = true + } + // If goto < label, + // then not a goto loop. + if n == origGoto && !labelReached { + return n, TRANS_EXIT + } + } + + // If label not reached, continue. + if !labelReached { + return n, TRANS_CONTINUE + } + + // NOTE: called redundantly + // for many goto stmts, + // idempotenct updates only. + switch n := n.(type) { + // Skip the body of these: + case *FuncLitExpr: + if len(ns) > 0 { + // inner funcs. + return n, TRANS_SKIP + } + return n, TRANS_CONTINUE + case *FuncDecl: + if len(ns) > 0 { + panic("unexpected inner func decl") + } + return n, TRANS_CONTINUE + // Otherwise mark stmt as gotoloop. + case Stmt: + // we're done if we + // re-encounter origGotoStmtm. + if n == origGoto { + n.SetAttribute( + ATTR_GOTOLOOP_STMT, + true) + return n, TRANS_EXIT // done + } + // otherwise set attribute. + n.SetAttribute( + ATTR_GOTOLOOP_STMT, + true) + return n, TRANS_CONTINUE + // Special case, maybe convert + // NameExprTypeDefine to + // NameExprTypeHeapDefine. + case *NameExpr: + if n.Type == NameExprTypeDefine { + n.Type = NameExprTypeHeapDefine + } + } + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) + } + } + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) +} + +// Find uses of loop names; those names that are defined as loop defines; +// defines within loops that are used as reference or captured in a closure +// later. Also happens to adjust the type (but not paths) of such usage. +// If there is no usage of the &name or as closure capture, a +// NameExprTypeHeapDefine gets demoted to NameExprTypeDefine in demoteHeapDefines(). +func findLoopUses1(ctx BlockNode, bn BlockNode) { + // create stack of BlockNodes. + var stack []BlockNode = make([]BlockNode, 0, 32) + var last BlockNode = ctx + stack = append(stack, last) + + // Iterate over all nodes recursively. + _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + defer doRecover(stack, n) + + if debug { + debug.Printf("findLoopUses1 %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + } + + switch stage { + // ---------------------------------------- + case TRANS_BLOCK: + pushInitBlock(n.(BlockNode), &last, &stack) + + // ---------------------------------------- + case TRANS_ENTER: + switch n := n.(type) { + case *NameExpr: + // Ignore non-block type paths + if n.Path.Type != VPBlock { + return n, TRANS_CONTINUE + } + switch n.Type { + case NameExprTypeNormal: + // Find the block where name is defined + dbn := last.GetBlockNodeForPath(nil, n.Path) + // if the name is loop defined, + lds, _ := dbn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) + if slices.Contains(lds, n.Name) { + fle, depth, found := findFirstClosure(stack, dbn) + if found { + // If across a closure, + // mark name as loop used. + addAttrHeapUse(dbn, n.Name) + // The path must stay same for now, + // used later in findLoopUses2. + idx := addHeapCapture(dbn, fle, n.Name) + // adjust NameExpr type. + n.Type = NameExprTypeHeapUse + n.Path.Depth = uint8(depth) + n.Path.Index = idx + } else { + if ftype == TRANS_REF_X { + // if used as a reference, + // mark name as loop used. + addAttrHeapUse(dbn, n.Name) + // Also adjust NameExpr type. + // We could do this later too. + n.Type = NameExprTypeHeapUse + } + } + } else { + // if the name is not loop defined, + // do nothing. + } + case NameExprTypeDefine: + // nothing to do. + case NameExprTypeHeapDefine: + // Set name in attribute, so later matches + // on NameExpr can know that this was loop defined + // on this block. + setAttrHeapDefine(last, n.Name) + case NameExprTypeHeapUse, NameExprTypeHeapClosure: + panic("unexpected node type") + } + } + return n, TRANS_CONTINUE + + // ---------------------------------------- + case TRANS_LEAVE: + // Pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) +} + +func assertNotHasName(names []Name, name Name) { + if slices.Contains(names, name) { + panic(fmt.Sprintf("name: %s already contained in names: %v", name, names)) + } +} + +func setAttrHeapDefine(bn BlockNode, name Name) { + bnLDs, _ := bn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) + assertNotHasName(bnLDs, name) + bnLDs = append(bnLDs, name) + bn.SetAttribute(ATTR_LOOP_DEFINES, bnLDs) +} + +func addAttrHeapUse(bn BlockNode, name Name) { + bnLUs, _ := bn.GetAttribute(ATTR_LOOP_USES).([]Name) + if slices.Contains(bnLUs, name) { + return + } else { + bnLUs = append(bnLUs, name) + bn.SetAttribute(ATTR_LOOP_USES, bnLUs) + return + } +} + +// adds ~name to fle static block and to heap captures atomically. +func addHeapCapture(dbn BlockNode, fle *FuncLitExpr, name Name) (idx uint16) { + for _, ne := range fle.HeapCaptures { + if ne.Name == name { + // assert ~name also already defined. + var ok bool + idx, ok = fle.GetLocalIndex("~" + name) + if !ok { + panic("~name not added to fle atomically") + } + return // already exists + } + } + + // define ~name to fle. + _, ok := fle.GetLocalIndex("~" + name) + if ok { + panic("~name already defined in fle") + } + + tv := dbn.GetValueRef(nil, name, true) + fle.Define("~"+name, tv.Copy(nil)) + + // add name to fle.HeapCaptures. + vp := fle.GetPathForName(nil, name) + vp.Depth -= 1 // minus 1 for fle itself. + ne := NameExpr{ + Path: vp, + Name: name, + Type: NameExprTypeHeapClosure, + } + fle.HeapCaptures = append(fle.HeapCaptures, ne) + + // find index after define + for i, n := range fle.GetBlockNames() { + if n == "~"+name { + idx = uint16(i) + return + } + } + + panic("should not happen, idx not found") +} + +// finds the first FuncLitExpr in the stack at or after stop. +// returns the depth of first closure, 1 if stop itself is a closure, +// or 0 if not found. +func findFirstClosure(stack []BlockNode, stop BlockNode) (fle *FuncLitExpr, depth int, found bool) { + redundant := 0 // count faux block + for i := len(stack) - 1; i >= 0; i-- { + stbn := stack[i] + switch stbn := stbn.(type) { + case *FuncLitExpr: + if stbn == stop { // if fle is stopBn, does not count, use last fle + return + } + fle = stbn + depth = len(stack) - 1 - redundant - i + 1 // +1 since 1 is lowest. + found = true + // even if found, continue iteration in case + // an earlier *FuncLitExpr is found. + case *IfCaseStmt, *SwitchClauseStmt: + if stbn == stop { + return + } + redundant++ + default: + if stbn == stop { + return + } + } + } + panic("stop not found in stack") +} + +// Convert non-loop uses of loop names to NameExprTypeHeapUse. +// Also, NameExprTypeHeapDefine gets demoted to NameExprTypeDefine if no actual +// usage was found that warrants a NameExprTypeHeapDefine. +func findLoopUses2(ctx BlockNode, bn BlockNode) { + // create stack of BlockNodes. + var stack []BlockNode = make([]BlockNode, 0, 32) + var last BlockNode = ctx + stack = append(stack, last) + + // Iterate over all nodes recursively. + _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + defer doRecover(stack, n) + + if debug { + debug.Printf("findLoopUses2 %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + } + + switch stage { + // ---------------------------------------- + case TRANS_BLOCK: + pushInitBlock(n.(BlockNode), &last, &stack) + + // ---------------------------------------- + case TRANS_ENTER: + switch n := n.(type) { + case *NameExpr: + // Ignore non-block type paths + if n.Path.Type != VPBlock { + return n, TRANS_CONTINUE + } + switch n.Type { + case NameExprTypeNormal: + // Find the block where name is defined + dbn := last.GetBlockNodeForPath(nil, n.Path) + // if the name is loop defined, + lds, _ := dbn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) + if slices.Contains(lds, n.Name) { + // if the name is actually loop used, + lus, _ := dbn.GetAttribute(ATTR_LOOP_USES).([]Name) + if slices.Contains(lus, n.Name) { + // change type finally to HeapUse. + n.Type = NameExprTypeHeapUse + } else { + // else, will be demoted in later clause. + } + } + case NameExprTypeHeapDefine: + // Find the block where name is defined + dbn := last.GetBlockNodeForPath(nil, n.Path) + // if the name is loop defined + lds, _ := dbn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) + if slices.Contains(lds, n.Name) { + // if the name is actually loop used + lus, _ := dbn.GetAttribute(ATTR_LOOP_USES).([]Name) + if !slices.Contains(lus, n.Name) { + // demote type finally to Define. + n.Type = NameExprTypeDefine + } + } + } + } + return n, TRANS_CONTINUE + + // ---------------------------------------- + case TRANS_LEAVE: + + // Defer pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + defer func() { + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + }() + + switch n := n.(type) { + case BlockNode: + lds, _ := n.GetAttribute(ATTR_LOOP_DEFINES).([]Name) + lus, _ := n.GetAttribute(ATTR_LOOP_USES).([]Name) + if len(lds) < len(lus) { + panic("defines should be a superset of used-defines") + } + // no need anymore + n.DelAttribute(ATTR_LOOP_USES) + n.DelAttribute(ATTR_LOOP_DEFINES) + } + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) +} + func isSwitchLabel(ns []Node, label Name) bool { for { swch := lastSwitch(ns) @@ -2514,37 +2988,38 @@ func isSwitchLabel(ns []Node, label Name) bool { } // Idempotent. +// Also makes sure the stack doesn't reach MaxUint8 in length. func pushInitBlock(bn BlockNode, last *BlockNode, stack *[]BlockNode) { if !bn.IsInitialized() { - bn.InitStaticBlock(bn, *last) + switch bn.(type) { + case *IfCaseStmt, *SwitchClauseStmt: + // skip faux block + bn.InitStaticBlock(bn, (*last).GetParentNode(nil)) + default: + bn.InitStaticBlock(bn, *last) + } } if bn.GetStaticBlock().Source != bn { panic("expected the source of a block node to be itself") } *last = bn *stack = append(*stack, bn) -} - -// like pushInitBlock(), but when the last block is a faux block, -// namely after SwitchStmt and IfStmt. -// Idempotent. -func pushInitRealBlock(bn BlockNode, last *BlockNode, stack *[]BlockNode) { - if !bn.IsInitialized() { - bn.InitStaticBlock(bn, (*last).GetParentNode(nil)) - } - if bn.GetStaticBlock().Source != bn { - panic("expected the source of a block node to be itself") + if len(*stack) >= math.MaxUint8 { + panic("block node depth reached maximum MaxUint8") } - *last = bn - *stack = append(*stack, bn) } // like pushInitBlock(), but when the last block is a faux block, // namely after SwitchStmt and IfStmt. // Not idempotent, as it calls bn.Define with reference to last's TV value slot. -func pushInitRealBlockAndCopy(bn BlockNode, last *BlockNode, stack *[]BlockNode) { +func pushInitBlockAndCopy(bn BlockNode, last *BlockNode, stack *[]BlockNode) { + if _, ok := bn.(*IfCaseStmt); !ok { + if _, ok := bn.(*SwitchClauseStmt); !ok { + panic("should not happen") + } + } orig := *last - pushInitRealBlock(bn, last, stack) + pushInitBlock(bn, last, stack) copyFromFauxBlock(bn, orig) } @@ -2750,6 +3225,7 @@ func evalConst(store Store, last BlockNode, x Expr) *ConstExpr { Source: x, TypedValue: cv, } + cx.SetLine(x.GetLine()) cx.SetAttribute(ATTR_PREPROCESSED, true) setConstAttrs(cx) return cx @@ -2758,6 +3234,7 @@ func evalConst(store Store, last BlockNode, x Expr) *ConstExpr { func constType(source Expr, t Type) *constTypeExpr { cx := &constTypeExpr{Source: source} cx.Type = t + cx.SetLine(source.GetLine()) cx.SetAttribute(ATTR_PREPROCESSED, true) return cx } @@ -3060,7 +3537,7 @@ func convertType(store Store, last BlockNode, x *Expr, t Type) { // convert x to destination type t func doConvertType(store Store, last BlockNode, x *Expr, t Type) { - cx := Expr(Call(constType(nil, t), *x)) + cx := Expr(Call(constType(*x, t), *x)) cx = Preprocess(store, last, cx).(Expr) *x = cx } @@ -3296,7 +3773,7 @@ func findUndefined2(store Store, last BlockNode, x Expr, t Type) (un Name) { panic("cannot elide unknown composite type") } ct = t - cx.Type = constType(nil, t) + cx.Type = constType(cx, t) } else { un = findUndefined(store, last, cx.Type) if un != "" { @@ -3880,10 +4357,6 @@ func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { } // If not DEFINE_LHS, yet is statically undefined, set path from parent. - - // NOTE: ValueDecl names don't need this distinction, as - // the transcriber doesn't enter any of the ValueDecl.NameExprs nodes, - // so this function never gets called for them. if !isDefineLHS { if last.GetStaticTypeOf(nil, nx.Name) == nil { // NOTE: We cannot simply call last.GetPathForName() as below here, @@ -4215,13 +4688,38 @@ func isLocallyDefined(bn BlockNode, n Name) bool { return true } +// r := 0 +// r, ok := 1, true +func isLocallyDefined2(bn BlockNode, n Name) bool { + _, isLocal := bn.GetLocalIndex(n) + return isLocal +} + // ---------------------------------------- -// SetNodeLocations +// setNodeLines & setNodeLocations -// Iterate over all block nodes recursively and sets location information -// based on sparse expectations, and ensures uniqueness of BlockNode.Locations. +func setNodeLines(n Node) { + lastLine := 0 + Transcribe(n, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + if stage != TRANS_ENTER { + return n, TRANS_CONTINUE + } + line := n.GetLine() + if line == lastLine { + } else if line == 0 { + line = lastLine + } else { + lastLine = line + } + n.SetLine(line) + return n, TRANS_CONTINUE + }) +} + +// Iterate over all nodes recursively and sets location information +// based on sparse expectations on block nodes, and ensures uniqueness of BlockNode.Locations. // Ensures uniqueness of BlockNode.Locations. -func SetNodeLocations(pkgPath string, fileName string, n Node) { +func setNodeLocations(pkgPath string, fileName string, n Node) { if n.GetAttribute(ATTR_LOCATIONED) == true { return // locations already set (typically n is a filenode). } @@ -4246,6 +4744,13 @@ func SetNodeLocations(pkgPath string, fileName string, n Node) { }) } +// XXX check node lines, uniqueness of locations, +// and also check location pkgpath and filename. +// Even after this is implemented, locations should not be used for logic. +func checkNodeLinesLocations(pkgPath string, fileName string, n Node) { + // TODO: XXX +} + // ---------------------------------------- // SaveBlockNodes diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 3710524130a..5913f13a0f7 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -845,6 +845,9 @@ func getChildObjects(val Value, more []Value) []Value { if bv, ok := cv.Closure.(*Block); ok { more = getSelfOrChildObjects(bv, more) } + for _, c := range cv.Captures { + more = getSelfOrChildObjects(c.V, more) + } return more case *BoundMethodValue: more = getChildObjects(cv.Func, more) // *FuncValue not object @@ -1142,6 +1145,7 @@ func copyValueWithRefs(val Value) Value { Source: source, Name: cv.Name, Closure: closure, + Captures: cv.Captures, FileName: cv.FileName, PkgPath: cv.PkgPath, NativePkg: cv.NativePkg, diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 0e6d89a7bf3..9913c434282 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -47,7 +47,7 @@ type Store interface { GetTypeSafe(tid TypeID) Type SetCacheType(Type) SetType(Type) - GetBlockNode(Location) BlockNode + GetBlockNode(Location) BlockNode // to get a PackageNode, use PackageNodeLocation(). GetBlockNodeSafe(Location) BlockNode SetBlockNode(BlockNode) // UNSTABLE diff --git a/gnovm/pkg/gnolang/transcribe.go b/gnovm/pkg/gnolang/transcribe.go index 28e97ff2b5b..dab539a8707 100644 --- a/gnovm/pkg/gnolang/transcribe.go +++ b/gnovm/pkg/gnolang/transcribe.go @@ -47,6 +47,7 @@ const ( TRANS_COMPOSITE_KEY TRANS_COMPOSITE_VALUE TRANS_FUNCLIT_TYPE + TRANS_FUNCLIT_HEAP_CAPTURE TRANS_FUNCLIT_BODY TRANS_FIELDTYPE_TYPE TRANS_FIELDTYPE_TAG @@ -100,6 +101,7 @@ const ( TRANS_IMPORT_PATH TRANS_CONST_TYPE TRANS_CONST_VALUE + TRANS_VAR_NAME // XXX stringer TRANS_VAR_TYPE TRANS_VAR_VALUE TRANS_TYPE_TYPE @@ -112,6 +114,7 @@ const ( // ENTER,CHILDS1,[BLOCK,CHILDS2]?,LEAVE sequence for that node, // i.e. skipping (the rest of) it; // - TRANS_BREAK to break out of looping in CHILDS1 or CHILDS2, +// but still perform TRANS_LEAVE. // - TRANS_EXIT to stop traversing altogether. // // Do not mutate ns. @@ -264,6 +267,14 @@ func transcribe(t Transform, ns []Node, ftype TransField, index int, n Node, nc if isStopOrSkip(nc, c) { return } + for idx := range cnn.HeapCaptures { + cnn.HeapCaptures[idx] = *(transcribe(t, nns, TRANS_FUNCLIT_HEAP_CAPTURE, idx, &cnn.HeapCaptures[idx], &c).(*NameExpr)) + if isBreak(c) { + break + } else if isStopOrSkip(nc, c) { + return + } + } cnn2, c2 := t(ns, ftype, index, cnn, TRANS_BLOCK) if isStopOrSkip(nc, c2) { nn = cnn2 @@ -692,6 +703,10 @@ func transcribe(t Transform, ns []Node, ftype TransField, index int, n Node, nc return } } + // XXX consider RHS, LHS, RHS, LHS, ... order. + for idx := range cnn.NameExprs { + cnn.NameExprs[idx] = *(transcribe(t, nns, TRANS_VAR_NAME, idx, &cnn.NameExprs[idx], &c).(*NameExpr)) + } for idx := range cnn.Values { cnn.Values[idx] = transcribe(t, nns, TRANS_VAR_VALUE, idx, cnn.Values[idx], &c).(Expr) if isBreak(c) { diff --git a/gnovm/pkg/gnolang/transfield_string.go b/gnovm/pkg/gnolang/transfield_string.go index 587ca7a7654..31afcf2be0d 100644 --- a/gnovm/pkg/gnolang/transfield_string.go +++ b/gnovm/pkg/gnolang/transfield_string.go @@ -29,68 +29,70 @@ func _() { _ = x[TRANS_COMPOSITE_KEY-18] _ = x[TRANS_COMPOSITE_VALUE-19] _ = x[TRANS_FUNCLIT_TYPE-20] - _ = x[TRANS_FUNCLIT_BODY-21] - _ = x[TRANS_FIELDTYPE_TYPE-22] - _ = x[TRANS_FIELDTYPE_TAG-23] - _ = x[TRANS_ARRAYTYPE_LEN-24] - _ = x[TRANS_ARRAYTYPE_ELT-25] - _ = x[TRANS_SLICETYPE_ELT-26] - _ = x[TRANS_INTERFACETYPE_METHOD-27] - _ = x[TRANS_CHANTYPE_VALUE-28] - _ = x[TRANS_FUNCTYPE_PARAM-29] - _ = x[TRANS_FUNCTYPE_RESULT-30] - _ = x[TRANS_MAPTYPE_KEY-31] - _ = x[TRANS_MAPTYPE_VALUE-32] - _ = x[TRANS_STRUCTTYPE_FIELD-33] - _ = x[TRANS_MAYBENATIVETYPE_TYPE-34] - _ = x[TRANS_ASSIGN_LHS-35] - _ = x[TRANS_ASSIGN_RHS-36] - _ = x[TRANS_BLOCK_BODY-37] - _ = x[TRANS_DECL_BODY-38] - _ = x[TRANS_DEFER_CALL-39] - _ = x[TRANS_EXPR_X-40] - _ = x[TRANS_FOR_INIT-41] - _ = x[TRANS_FOR_COND-42] - _ = x[TRANS_FOR_POST-43] - _ = x[TRANS_FOR_BODY-44] - _ = x[TRANS_GO_CALL-45] - _ = x[TRANS_IF_INIT-46] - _ = x[TRANS_IF_COND-47] - _ = x[TRANS_IF_BODY-48] - _ = x[TRANS_IF_ELSE-49] - _ = x[TRANS_IF_CASE_BODY-50] - _ = x[TRANS_INCDEC_X-51] - _ = x[TRANS_RANGE_X-52] - _ = x[TRANS_RANGE_KEY-53] - _ = x[TRANS_RANGE_VALUE-54] - _ = x[TRANS_RANGE_BODY-55] - _ = x[TRANS_RETURN_RESULT-56] - _ = x[TRANS_PANIC_EXCEPTION-57] - _ = x[TRANS_SELECT_CASE-58] - _ = x[TRANS_SELECTCASE_COMM-59] - _ = x[TRANS_SELECTCASE_BODY-60] - _ = x[TRANS_SEND_CHAN-61] - _ = x[TRANS_SEND_VALUE-62] - _ = x[TRANS_SWITCH_INIT-63] - _ = x[TRANS_SWITCH_X-64] - _ = x[TRANS_SWITCH_CASE-65] - _ = x[TRANS_SWITCHCASE_CASE-66] - _ = x[TRANS_SWITCHCASE_BODY-67] - _ = x[TRANS_FUNC_RECV-68] - _ = x[TRANS_FUNC_TYPE-69] - _ = x[TRANS_FUNC_BODY-70] - _ = x[TRANS_IMPORT_PATH-71] - _ = x[TRANS_CONST_TYPE-72] - _ = x[TRANS_CONST_VALUE-73] - _ = x[TRANS_VAR_TYPE-74] - _ = x[TRANS_VAR_VALUE-75] - _ = x[TRANS_TYPE_TYPE-76] - _ = x[TRANS_FILE_BODY-77] + _ = x[TRANS_FUNCLIT_HEAP_CAPTURE-21] + _ = x[TRANS_FUNCLIT_BODY-22] + _ = x[TRANS_FIELDTYPE_TYPE-23] + _ = x[TRANS_FIELDTYPE_TAG-24] + _ = x[TRANS_ARRAYTYPE_LEN-25] + _ = x[TRANS_ARRAYTYPE_ELT-26] + _ = x[TRANS_SLICETYPE_ELT-27] + _ = x[TRANS_INTERFACETYPE_METHOD-28] + _ = x[TRANS_CHANTYPE_VALUE-29] + _ = x[TRANS_FUNCTYPE_PARAM-30] + _ = x[TRANS_FUNCTYPE_RESULT-31] + _ = x[TRANS_MAPTYPE_KEY-32] + _ = x[TRANS_MAPTYPE_VALUE-33] + _ = x[TRANS_STRUCTTYPE_FIELD-34] + _ = x[TRANS_MAYBENATIVETYPE_TYPE-35] + _ = x[TRANS_ASSIGN_LHS-36] + _ = x[TRANS_ASSIGN_RHS-37] + _ = x[TRANS_BLOCK_BODY-38] + _ = x[TRANS_DECL_BODY-39] + _ = x[TRANS_DEFER_CALL-40] + _ = x[TRANS_EXPR_X-41] + _ = x[TRANS_FOR_INIT-42] + _ = x[TRANS_FOR_COND-43] + _ = x[TRANS_FOR_POST-44] + _ = x[TRANS_FOR_BODY-45] + _ = x[TRANS_GO_CALL-46] + _ = x[TRANS_IF_INIT-47] + _ = x[TRANS_IF_COND-48] + _ = x[TRANS_IF_BODY-49] + _ = x[TRANS_IF_ELSE-50] + _ = x[TRANS_IF_CASE_BODY-51] + _ = x[TRANS_INCDEC_X-52] + _ = x[TRANS_RANGE_X-53] + _ = x[TRANS_RANGE_KEY-54] + _ = x[TRANS_RANGE_VALUE-55] + _ = x[TRANS_RANGE_BODY-56] + _ = x[TRANS_RETURN_RESULT-57] + _ = x[TRANS_PANIC_EXCEPTION-58] + _ = x[TRANS_SELECT_CASE-59] + _ = x[TRANS_SELECTCASE_COMM-60] + _ = x[TRANS_SELECTCASE_BODY-61] + _ = x[TRANS_SEND_CHAN-62] + _ = x[TRANS_SEND_VALUE-63] + _ = x[TRANS_SWITCH_INIT-64] + _ = x[TRANS_SWITCH_X-65] + _ = x[TRANS_SWITCH_CASE-66] + _ = x[TRANS_SWITCHCASE_CASE-67] + _ = x[TRANS_SWITCHCASE_BODY-68] + _ = x[TRANS_FUNC_RECV-69] + _ = x[TRANS_FUNC_TYPE-70] + _ = x[TRANS_FUNC_BODY-71] + _ = x[TRANS_IMPORT_PATH-72] + _ = x[TRANS_CONST_TYPE-73] + _ = x[TRANS_CONST_VALUE-74] + _ = x[TRANS_VAR_NAME-75] + _ = x[TRANS_VAR_TYPE-76] + _ = x[TRANS_VAR_VALUE-77] + _ = x[TRANS_TYPE_TYPE-78] + _ = x[TRANS_FILE_BODY-79] } -const _TransField_name = "TRANS_ROOTTRANS_BINARY_LEFTTRANS_BINARY_RIGHTTRANS_CALL_FUNCTRANS_CALL_ARGTRANS_INDEX_XTRANS_INDEX_INDEXTRANS_SELECTOR_XTRANS_SLICE_XTRANS_SLICE_LOWTRANS_SLICE_HIGHTRANS_SLICE_MAXTRANS_STAR_XTRANS_REF_XTRANS_TYPEASSERT_XTRANS_TYPEASSERT_TYPETRANS_UNARY_XTRANS_COMPOSITE_TYPETRANS_COMPOSITE_KEYTRANS_COMPOSITE_VALUETRANS_FUNCLIT_TYPETRANS_FUNCLIT_BODYTRANS_FIELDTYPE_TYPETRANS_FIELDTYPE_TAGTRANS_ARRAYTYPE_LENTRANS_ARRAYTYPE_ELTTRANS_SLICETYPE_ELTTRANS_INTERFACETYPE_METHODTRANS_CHANTYPE_VALUETRANS_FUNCTYPE_PARAMTRANS_FUNCTYPE_RESULTTRANS_MAPTYPE_KEYTRANS_MAPTYPE_VALUETRANS_STRUCTTYPE_FIELDTRANS_MAYBENATIVETYPE_TYPETRANS_ASSIGN_LHSTRANS_ASSIGN_RHSTRANS_BLOCK_BODYTRANS_DECL_BODYTRANS_DEFER_CALLTRANS_EXPR_XTRANS_FOR_INITTRANS_FOR_CONDTRANS_FOR_POSTTRANS_FOR_BODYTRANS_GO_CALLTRANS_IF_INITTRANS_IF_CONDTRANS_IF_BODYTRANS_IF_ELSETRANS_IF_CASE_BODYTRANS_INCDEC_XTRANS_RANGE_XTRANS_RANGE_KEYTRANS_RANGE_VALUETRANS_RANGE_BODYTRANS_RETURN_RESULTTRANS_PANIC_EXCEPTIONTRANS_SELECT_CASETRANS_SELECTCASE_COMMTRANS_SELECTCASE_BODYTRANS_SEND_CHANTRANS_SEND_VALUETRANS_SWITCH_INITTRANS_SWITCH_XTRANS_SWITCH_CASETRANS_SWITCHCASE_CASETRANS_SWITCHCASE_BODYTRANS_FUNC_RECVTRANS_FUNC_TYPETRANS_FUNC_BODYTRANS_IMPORT_PATHTRANS_CONST_TYPETRANS_CONST_VALUETRANS_VAR_TYPETRANS_VAR_VALUETRANS_TYPE_TYPETRANS_FILE_BODY" +const _TransField_name = "TRANS_ROOTTRANS_BINARY_LEFTTRANS_BINARY_RIGHTTRANS_CALL_FUNCTRANS_CALL_ARGTRANS_INDEX_XTRANS_INDEX_INDEXTRANS_SELECTOR_XTRANS_SLICE_XTRANS_SLICE_LOWTRANS_SLICE_HIGHTRANS_SLICE_MAXTRANS_STAR_XTRANS_REF_XTRANS_TYPEASSERT_XTRANS_TYPEASSERT_TYPETRANS_UNARY_XTRANS_COMPOSITE_TYPETRANS_COMPOSITE_KEYTRANS_COMPOSITE_VALUETRANS_FUNCLIT_TYPETRANS_FUNCLIT_HEAP_CAPTURETRANS_FUNCLIT_BODYTRANS_FIELDTYPE_TYPETRANS_FIELDTYPE_TAGTRANS_ARRAYTYPE_LENTRANS_ARRAYTYPE_ELTTRANS_SLICETYPE_ELTTRANS_INTERFACETYPE_METHODTRANS_CHANTYPE_VALUETRANS_FUNCTYPE_PARAMTRANS_FUNCTYPE_RESULTTRANS_MAPTYPE_KEYTRANS_MAPTYPE_VALUETRANS_STRUCTTYPE_FIELDTRANS_MAYBENATIVETYPE_TYPETRANS_ASSIGN_LHSTRANS_ASSIGN_RHSTRANS_BLOCK_BODYTRANS_DECL_BODYTRANS_DEFER_CALLTRANS_EXPR_XTRANS_FOR_INITTRANS_FOR_CONDTRANS_FOR_POSTTRANS_FOR_BODYTRANS_GO_CALLTRANS_IF_INITTRANS_IF_CONDTRANS_IF_BODYTRANS_IF_ELSETRANS_IF_CASE_BODYTRANS_INCDEC_XTRANS_RANGE_XTRANS_RANGE_KEYTRANS_RANGE_VALUETRANS_RANGE_BODYTRANS_RETURN_RESULTTRANS_PANIC_EXCEPTIONTRANS_SELECT_CASETRANS_SELECTCASE_COMMTRANS_SELECTCASE_BODYTRANS_SEND_CHANTRANS_SEND_VALUETRANS_SWITCH_INITTRANS_SWITCH_XTRANS_SWITCH_CASETRANS_SWITCHCASE_CASETRANS_SWITCHCASE_BODYTRANS_FUNC_RECVTRANS_FUNC_TYPETRANS_FUNC_BODYTRANS_IMPORT_PATHTRANS_CONST_TYPETRANS_CONST_VALUETRANS_VAR_NAMETRANS_VAR_TYPETRANS_VAR_VALUETRANS_TYPE_TYPETRANS_FILE_BODY" -var _TransField_index = [...]uint16{0, 10, 27, 45, 60, 74, 87, 104, 120, 133, 148, 164, 179, 191, 202, 220, 241, 254, 274, 293, 314, 332, 350, 370, 389, 408, 427, 446, 472, 492, 512, 533, 550, 569, 591, 617, 633, 649, 665, 680, 696, 708, 722, 736, 750, 764, 777, 790, 803, 816, 829, 847, 861, 874, 889, 906, 922, 941, 962, 979, 1000, 1021, 1036, 1052, 1069, 1083, 1100, 1121, 1142, 1157, 1172, 1187, 1204, 1220, 1237, 1251, 1266, 1281, 1296} +var _TransField_index = [...]uint16{0, 10, 27, 45, 60, 74, 87, 104, 120, 133, 148, 164, 179, 191, 202, 220, 241, 254, 274, 293, 314, 332, 358, 376, 396, 415, 434, 453, 472, 498, 518, 538, 559, 576, 595, 617, 643, 659, 675, 691, 706, 722, 734, 748, 762, 776, 790, 803, 816, 829, 842, 855, 873, 887, 900, 915, 932, 948, 967, 988, 1005, 1026, 1047, 1062, 1078, 1095, 1109, 1126, 1147, 1168, 1183, 1198, 1213, 1230, 1246, 1263, 1277, 1291, 1306, 1321, 1336} func (i TransField) String() string { if i >= TransField(len(_TransField_index)-1) { diff --git a/gnovm/pkg/gnolang/type_check.go b/gnovm/pkg/gnolang/type_check.go index 2dec832fd0d..f86c44e7921 100644 --- a/gnovm/pkg/gnolang/type_check.go +++ b/gnovm/pkg/gnolang/type_check.go @@ -855,8 +855,8 @@ func (x *AssignStmt) AssertCompatible(store Store, last BlockNode) { if x.Op == ASSIGN { // check assignable for i, lx := range x.Lhs { + assertValidAssignLhs(store, last, lx) if !isBlankIdentifier(lx) { - assertValidAssignLhs(store, last, lx) lxt := evalStaticTypeOf(store, last, lx) assertAssignableTo(cft.Results[i].Type, lxt, false) } @@ -868,15 +868,16 @@ func (x *AssignStmt) AssertCompatible(store Store, last BlockNode) { panic("should not happen") } if x.Op == ASSIGN { - // check assignable to first value + // check first value + assertValidAssignLhs(store, last, x.Lhs[0]) if !isBlankIdentifier(x.Lhs[0]) { // see composite3.gno - assertValidAssignLhs(store, last, x.Lhs[0]) dt := evalStaticTypeOf(store, last, x.Lhs[0]) ift := evalStaticTypeOf(store, last, cx) assertAssignableTo(ift, dt, false) } + // check second value + assertValidAssignLhs(store, last, x.Lhs[1]) if !isBlankIdentifier(x.Lhs[1]) { // see composite3.gno - assertValidAssignLhs(store, last, x.Lhs[1]) dt := evalStaticTypeOf(store, last, x.Lhs[1]) if dt.Kind() != BoolKind { // typed, not bool panic(fmt.Sprintf("want bool type got %v", dt)) @@ -889,8 +890,8 @@ func (x *AssignStmt) AssertCompatible(store Store, last BlockNode) { panic("should not happen") } if x.Op == ASSIGN { + assertValidAssignLhs(store, last, x.Lhs[0]) if !isBlankIdentifier(x.Lhs[0]) { - assertValidAssignLhs(store, last, x.Lhs[0]) lt := evalStaticTypeOf(store, last, x.Lhs[0]) if _, ok := cx.X.(*NameExpr); ok { rt := evalStaticTypeOf(store, last, cx.X) @@ -906,8 +907,9 @@ func (x *AssignStmt) AssertCompatible(store Store, last BlockNode) { } } } + + assertValidAssignLhs(store, last, x.Lhs[1]) if !isBlankIdentifier(x.Lhs[1]) { - assertValidAssignLhs(store, last, x.Lhs[1]) dt := evalStaticTypeOf(store, last, x.Lhs[1]) if dt != nil && dt.Kind() != BoolKind { // typed, not bool panic(fmt.Sprintf("want bool type got %v", dt)) @@ -973,7 +975,17 @@ func (x *AssignStmt) AssertCompatible(store Store, last BlockNode) { func assertValidAssignLhs(store Store, last BlockNode, lx Expr) { shouldPanic := true switch clx := lx.(type) { - case *NameExpr, *StarExpr, *SelectorExpr: + case *NameExpr: + if clx.Name == blankIdentifier { + shouldPanic = false + } else if clx.Path.Type == VPUverse { + panic(fmt.Sprintf("cannot assign to uverse %v", clx.Name)) + } else if last.GetIsConst(store, clx.Name) { + panic(fmt.Sprintf("cannot assign to const %v", clx.Name)) + } else { + shouldPanic = false + } + case *StarExpr, *SelectorExpr: shouldPanic = false case *IndexExpr: xt := evalStaticTypeOf(store, last, clx.X) @@ -1017,7 +1029,7 @@ func isComparison(op Word) bool { // it returns true, indicating a swap is needed. func shouldSwapOnSpecificity(t1, t2 Type) bool { // check nil - if t1 == nil { // see test file 0f46 + if t1 == nil { return false // also with both nil } else if t2 == nil { return true @@ -1056,7 +1068,7 @@ func shouldSwapOnSpecificity(t1, t2 Type) bool { func isBlankIdentifier(x Expr) bool { if nx, ok := x.(*NameExpr); ok { - return nx.Name == "_" + return nx.Name == blankIdentifier } return false } diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index b43f623ea99..eedb71ffa73 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -69,6 +69,7 @@ func (*PackageType) assertType() {} func (*ChanType) assertType() {} func (*NativeType) assertType() {} func (blockType) assertType() {} +func (heapItemType) assertType() {} func (*tupleType) assertType() {} func (RefType) assertType() {} func (MaybeNativeType) assertType() {} @@ -1964,6 +1965,35 @@ func (bt blockType) IsNamed() bool { panic("blockType has no property called named") } +// ---------------------------------------- +// heapItemType + +type heapItemType struct{} // no data + +func (bt heapItemType) Kind() Kind { + return HeapItemKind +} + +func (bt heapItemType) TypeID() TypeID { + return typeid("heapitem") +} + +func (bt heapItemType) String() string { + return "heapitem" +} + +func (bt heapItemType) Elem() Type { + panic("heapItemType has no elem type") +} + +func (bt heapItemType) GetPkgPath() string { + panic("heapItemType has no package path") +} + +func (bt heapItemType) IsNamed() bool { + panic("heapItemType has no property called named") +} + // ---------------------------------------- // tupleType @@ -2118,9 +2148,10 @@ const ( MapKind TypeKind // not in go. // UnsafePointerKind - BlockKind // not in go. - TupleKind // not in go. - RefTypeKind // not in go. + BlockKind // not in go. + HeapItemKind // not in go. + TupleKind // not in go. + RefTypeKind // not in go. ) // This is generally slower than switching on baseOf(t). @@ -2193,6 +2224,8 @@ func KindOf(t Type) Kind { return t.Kind() case blockType: return BlockKind + case heapItemType: + return HeapItemKind case *tupleType: return TupleKind case RefType: diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 2761d3f574b..68c2967811f 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -534,12 +534,13 @@ func (sv *StructValue) Copy(alloc *Allocator) *StructValue { // makes construction TypedValue{T:*FuncType{},V:*FuncValue{}} // faster. type FuncValue struct { - Type Type // includes unbound receiver(s) - IsMethod bool // is an (unbound) method - Source BlockNode // for block mem allocation - Name Name // name of function/method - Closure Value // *Block or RefValue to closure (may be nil for file blocks; lazy) - FileName Name // file name where declared + Type Type // includes unbound receiver(s) + IsMethod bool // is an (unbound) method + Source BlockNode // for block mem allocation + Name Name // name of function/method + Closure Value // *Block or RefValue to closure (may be nil for file blocks; lazy) + Captures []TypedValue `json:",omitempty"` // HeapItemValues captured from closure. + FileName Name // file name where declared PkgPath string NativePkg string // for native bindings through NativeStore NativeName Name // not redundant with Name; this cannot be changed in userspace @@ -1645,10 +1646,10 @@ func (tv *TypedValue) Assign(alloc *Allocator, tv2 TypedValue, cu bool) { // or binary operations. When a pointer is to be // allocated, *Allocator.AllocatePointer() is called separately, // as in OpRef. -func (tv *TypedValue) GetPointerTo(alloc *Allocator, store Store, path ValuePath) PointerValue { +func (tv *TypedValue) GetPointerToFromTV(alloc *Allocator, store Store, path ValuePath) PointerValue { if debug { if tv.IsUndefined() { - panic("GetPointerTo() on undefined value") + panic("GetPointerToFromTV() on undefined value") } } @@ -1867,7 +1868,7 @@ func (tv *TypedValue) GetPointerTo(alloc *Allocator, store Store, path ValuePath } bv := *dtv for i, path := range tr { - ptr := bv.GetPointerTo(alloc, store, path) + ptr := bv.GetPointerToFromTV(alloc, store, path) if i == len(tr)-1 { return ptr // done } @@ -2436,6 +2437,70 @@ func (b *Block) GetPointerTo(store Store, path ValuePath) PointerValue { return b.GetPointerToInt(store, int(path.Index)) } +// Convenience +func (b *Block) GetPointerToMaybeHeapUse(store Store, nx *NameExpr) PointerValue { + switch nx.Type { + case NameExprTypeNormal: + return b.GetPointerTo(store, nx.Path) + case NameExprTypeHeapUse: + return b.GetPointerToHeapUse(store, nx.Path) + case NameExprTypeHeapClosure: + panic("should not happen with type heap closure") + default: + panic("unexpected NameExpr type for GetPointerToMaybeHeapUse") + } +} + +// Convenience +func (b *Block) GetPointerToMaybeHeapDefine(store Store, nx *NameExpr) PointerValue { + switch nx.Type { + case NameExprTypeNormal: + return b.GetPointerTo(store, nx.Path) + case NameExprTypeDefine: + return b.GetPointerTo(store, nx.Path) + case NameExprTypeHeapDefine: + return b.GetPointerToHeapDefine(store, nx.Path) + default: + panic("unexpected NameExpr type for GetPointerToMaybeHeapDefine") + } +} + +// First defines a new HeapItemValue. +// This gets called from NameExprTypeHeapDefine name expressions. +func (b *Block) GetPointerToHeapDefine(store Store, path ValuePath) PointerValue { + ptr := b.GetPointerTo(store, path) + hiv := &HeapItemValue{} + // point to a heapItem + *ptr.TV = TypedValue{ + T: heapItemType{}, + V: hiv, + } + + return PointerValue{ + TV: &hiv.Value, + Base: hiv, + Index: 0, + } +} + +// Assumes a HeapItemValue, and gets inner pointer. +// This gets called from NameExprTypeHeapUse name expressions. +func (b *Block) GetPointerToHeapUse(store Store, path ValuePath) PointerValue { + ptr := b.GetPointerTo(store, path) + if _, ok := ptr.TV.T.(heapItemType); !ok { + panic("should not happen, should be heapItemType") + } + if _, ok := ptr.TV.V.(*HeapItemValue); !ok { + panic("should not happen, should be HeapItemValue") + } + + return PointerValue{ + TV: &ptr.TV.V.(*HeapItemValue).Value, + Base: ptr.TV.V, + Index: 0, + } +} + // Result is used has lhs for any assignments to "_". func (b *Block) GetBlankRef() *TypedValue { return &b.Blank diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index 1be2a0516f9..f45beffe648 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -110,7 +110,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, stacktraceWanted, maxAlloc, send, preWanted := wantedFromComment(path) if pkgPath == "" { pkgPath = "main" } @@ -377,6 +377,28 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { } } } + case "Preprocessed": + // check preprocessed AST. + pn := store.GetBlockNode(gno.PackageNodeLocation(pkgPath)) + pre := pn.(*gno.PackageNode).FileSet.Files[0].String() + if pre != preWanted { + if f.syncWanted { + // write error to file + replaceWantedInPlace(path, "Preprocessed", pre) + } else { + // panic so tests immediately fail (for now). + diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(preWanted), + B: difflib.SplitLines(pre), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) + } + } case "Stacktrace": if stacktraceWanted != "" { var stacktrace string @@ -388,22 +410,27 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { 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)) + if f.syncWanted { + // write stacktrace to file + replaceWantedInPlace(path, "Stacktrace", stacktrace) + } else { + 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 } } } @@ -421,7 +448,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { 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, stacktrace string, maxAlloc int64, send std.Coins, pre string) { fset := token.NewFileSet() f, err2 := parser.ParseFile(fset, p, nil, parser.ParseComments) if err2 != nil { @@ -463,6 +490,10 @@ 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, "Preprocessed:\n") { + pre = strings.TrimPrefix(text, "Preprocessed:\n") + pre = strings.TrimSpace(pre) + directives = append(directives, "Preprocessed") } else if strings.HasPrefix(text, "Stacktrace:\n") { stacktrace = strings.TrimPrefix(text, "Stacktrace:\n") stacktrace = strings.TrimSpace(stacktrace) diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index 5bdd878c146..d61170334d7 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -1,10 +1,6 @@ // PKGPATH: gno.land/r/test package test -import ( - "fmt" -) - type ( word uint nat []word @@ -226,7 +222,7 @@ func main() { // "Location": { // "Column": "1", // "File": "main.gno", -// "Line": "20", +// "Line": "16", // "PkgPath": "gno.land/r/test" // } // }, diff --git a/gnovm/tests/files/heap_alloc_defer.gno b/gnovm/tests/files/heap_alloc_defer.gno new file mode 100644 index 00000000000..788d9326695 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_defer.gno @@ -0,0 +1,37 @@ +package main + +type Foo struct { + num int + f func() +} + +func main() { + s := []Foo{ + { + num: 1, + f: func() { println("hello") }, + }, + { + num: 2, + f: func() { println("hola") }, + }, + } + + // tt is heap defined every iteration, + // different with for loopvar spec. + for _, tt := range s { + f := func() { + println(tt.num) + } + f() + defer func() { + tt.f() + }() + } +} + +// Output: +// 1 +// 2 +// hola +// hola diff --git a/gnovm/tests/files/heap_alloc_defer2.gno b/gnovm/tests/files/heap_alloc_defer2.gno new file mode 100644 index 00000000000..dc865b1a430 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_defer2.gno @@ -0,0 +1,28 @@ +package main + +type rand struct{} + +func (r *rand) Seed() { + println("seed...") +} + +func fromSeed() *rand { + return &rand{} +} + +func genResult(s0 string, x int) (int, bool) { + z := 0 + println(z) + r := fromSeed() + defer func() { r.Seed() }() + + return -1, true +} + +func main() { + genResult("hey", 0) +} + +// Output: +// 0 +// seed... diff --git a/gnovm/tests/files/heap_alloc_forloop1.gno b/gnovm/tests/files/heap_alloc_forloop1.gno new file mode 100644 index 00000000000..c166bf8e167 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop1.gno @@ -0,0 +1,31 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + for i := 0; i < 3; i++ { + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 3 +// s1[1] is: 3 +// s1[2] is: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop1a.gno b/gnovm/tests/files/heap_alloc_forloop1a.gno new file mode 100644 index 00000000000..6d0895902bd --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop1a.gno @@ -0,0 +1,39 @@ +package main + +import "fmt" + +type Int int + +var s1 []*Int + +func inc2(j *Int) { + *j = *j + 2 // Just as an example, increment j by 2. +} + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + for i := Int(0); i < 10; inc2(&i) { + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; import fmt fmt; type Int (const-type main.Int); var s1 []*(Int); func inc2(j *(Int)) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); for i := (const (0 main.Int)); i<~VPBlock(1,0)> < (const (10 main.Int)); inc2(&(i<~VPBlock(1,0)>)) { s1 = (const (append func(x []*main.Int,args ...*main.Int)(res []*main.Int)))(s1, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 10 +// s1[1] is: 10 +// s1[2] is: 10 +// s1[3] is: 10 +// s1[4] is: 10 diff --git a/gnovm/tests/files/heap_alloc_forloop1b.gno b/gnovm/tests/files/heap_alloc_forloop1b.gno new file mode 100644 index 00000000000..35b167e4168 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop1b.gno @@ -0,0 +1,37 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + for i := 0; i < 3; i++ { + r := i + r, ok := 0, true + println(ok, r) + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { r := i<~VPBlock(1,0)>; r, ok := (const (0 int)), (const (true bool)); (const (println func(xs ...interface{})()))(ok, r); s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } + +// Output: +// true 0 +// true 0 +// true 0 +// s1[0] is: 3 +// s1[1] is: 3 +// s1[2] is: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop2.gno b/gnovm/tests/files/heap_alloc_forloop2.gno new file mode 100644 index 00000000000..aa7f6e44dd3 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop2.gno @@ -0,0 +1,33 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + for i := 0; i < 3; i++ { + z := i + 1 + s1 = append(s1, &z) + } +} + +func main() { + forLoopRef() +} + +// This does make 'z' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of z and z<~...>. + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i + (const (1 int)); s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(z<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 1 +// s1[1] is: 2 +// s1[2] is: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop2a.gno b/gnovm/tests/files/heap_alloc_forloop2a.gno new file mode 100644 index 00000000000..be4b089ccad --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop2a.gno @@ -0,0 +1,34 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + for i := 0; i < 3; i++ { + z := i + s1 = append(s1, &z) + z++ + } +} + +func main() { + forLoopRef() +} + +// This does make 'z' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of z and z<~...>. + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(z<~VPBlock(1,1)>)); z<~VPBlock(1,1)>++ } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 1 +// s1[1] is: 2 +// s1[2] is: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop3.gno b/gnovm/tests/files/heap_alloc_forloop3.gno new file mode 100644 index 00000000000..91c9b627120 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop3.gno @@ -0,0 +1,33 @@ +package main + +type f func() + +var fs []f + +func forLoopClosure() { + defer func() { + for _, f := range fs { + f() + } + }() + + for i := 0; i < 3; i++ { + z := i + fs = append(fs, func() { println(z) }) + } +} + +func main() { + forLoopClosure() +} + +// This does make 'z' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of z and z<()~...>. + +// Preprocessed: +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; fs = (const (append func(x []main.f,args ...main.f)(res []main.f)))(fs, (const-type main.f)(func func(){ (const (println func(xs ...interface{})()))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop3a.gno b/gnovm/tests/files/heap_alloc_forloop3a.gno new file mode 100644 index 00000000000..fd361e7134e --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop3a.gno @@ -0,0 +1,38 @@ +package main + +type f func() + +var fs []f + +func forLoopClosure() { + defer func() { + for _, f := range fs { + f() + } + }() + + for i := 0; i < 3; i++ { + x := i + println(x) + z := i + fs = append(fs, func() { println(z) }) + } +} + +func main() { + forLoopClosure() +} + +// This does make 'z' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of z and z<()~...>. + +// Preprocessed: +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; (const (println func(xs ...interface{})()))(x); z := i; fs = (const (append func(x []main.f,args ...main.f)(res []main.f)))(fs, (const-type main.f)(func func(){ (const (println func(xs ...interface{})()))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } + +// Output: +// 0 +// 1 +// 2 +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop4.gno b/gnovm/tests/files/heap_alloc_forloop4.gno new file mode 100644 index 00000000000..3cddb1a60fe --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop4.gno @@ -0,0 +1,31 @@ +package main + +type f func() + +var fs []f + +func forLoopClosure() { + defer func() { + for _, f := range fs { + f() + } + }() + + for i := 0; i < 3; i++ { + fs = append(fs, func() { println(i) }) + } +} + +func main() { + forLoopClosure() +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs = (const (append func(x []main.f,args ...main.f)(res []main.f)))(fs, (const-type main.f)(func func(){ (const (println func(xs ...interface{})()))(i<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } + +// Output: +// 3 +// 3 +// 3 diff --git a/gnovm/tests/files/heap_alloc_forloop5.gno b/gnovm/tests/files/heap_alloc_forloop5.gno new file mode 100644 index 00000000000..4f563ec866b --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop5.gno @@ -0,0 +1,32 @@ +package main + +type f func() + +var fs []f + +func forLoopClosure() { + defer func() { + for _, f := range fs { + f() + } + }() + + for i := 0; i < 3; i++ { + fs = append(fs, func() { + z := i + println(z) + }) + } +} + +func main() { + forLoopClosure() +} + +// Preprocessed: +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs = (const (append func(x []main.f,args ...main.f)(res []main.f)))(fs, (const-type main.f)(func func(){ z := i<~VPBlock(1,1)>; (const (println func(xs ...interface{})()))(z) }>)) } }; func main() { forLoopClosure() } } + +// Output: +// 3 +// 3 +// 3 diff --git a/gnovm/tests/files/heap_alloc_forloop5a.gno b/gnovm/tests/files/heap_alloc_forloop5a.gno new file mode 100644 index 00000000000..039be2b86a8 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop5a.gno @@ -0,0 +1,33 @@ +package main + +type f func() + +var fs []f + +func forLoopClosure() { + defer func() { + for _, f := range fs { + f() + } + }() + + for i := 0; i < 3; i++ { + x := i + fs = append(fs, func() { + z := x + println(z) + }) + } +} + +func main() { + forLoopClosure() +} + +// Preprocessed: +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; fs = (const (append func(x []main.f,args ...main.f)(res []main.f)))(fs, (const-type main.f)(func func(){ z := x<~VPBlock(1,1)>; (const (println func(xs ...interface{})()))(z) }>)) } }; func main() { forLoopClosure() } } + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6.gno b/gnovm/tests/files/heap_alloc_forloop6.gno new file mode 100644 index 00000000000..6cfa8a65fc8 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6.gno @@ -0,0 +1,25 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 3; i++ { + z := i + f := func() int { + return z + } + fns = append(fns, f) + } + + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; f := func func() (const-type int){ return z<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6a.gno b/gnovm/tests/files/heap_alloc_forloop6a.gno new file mode 100644 index 00000000000..6365fcd8c62 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6a.gno @@ -0,0 +1,26 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 5; i++ { + f := func() int { + return i + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (5 int)); i<~VPBlock(1,0)>++ { f := func func() (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 5 +// 5 +// 5 +// 5 +// 5 diff --git a/gnovm/tests/files/heap_alloc_forloop6b.gno b/gnovm/tests/files/heap_alloc_forloop6b.gno new file mode 100644 index 00000000000..73d9e5cd6a7 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6b.gno @@ -0,0 +1,25 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 2; i++ { + x := i + y := 0 + f := func() int { + x += y + x += 1 + return x + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (0 int)); f := func func() (const-type int){ x<~VPBlock(1,1)> += y<~VPBlock(1,2)>; x<~VPBlock(1,1)> += (const (1 int)); return x<~VPBlock(1,1)> }, y<()~VPBlock(1,2)>>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6c.gno b/gnovm/tests/files/heap_alloc_forloop6c.gno new file mode 100644 index 00000000000..f8d2d410f6c --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6c.gno @@ -0,0 +1,23 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 2; i++ { + f := func() int { + return i + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { f := func func() (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 2 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6f.gno b/gnovm/tests/files/heap_alloc_forloop6f.gno new file mode 100644 index 00000000000..fcc2cdfdcc1 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6f.gno @@ -0,0 +1,26 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 5; i++ { + var x int + f := func() int { + return x + } + x = i + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { var x (const-type int); f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; x<~VPBlock(1,1)> = i; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 +// 2 +// 3 +// 4 diff --git a/gnovm/tests/files/heap_alloc_forloop6g.gno b/gnovm/tests/files/heap_alloc_forloop6g.gno new file mode 100644 index 00000000000..4ff7856c97c --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6g.gno @@ -0,0 +1,27 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 5; i++ { + x := i + { // another block + f := func() int { + return x + } + fns = append(fns, f) + } + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { x := i; { f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) } }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 +// 2 +// 3 +// 4 diff --git a/gnovm/tests/files/heap_alloc_forloop6h.gno b/gnovm/tests/files/heap_alloc_forloop6h.gno new file mode 100644 index 00000000000..75b84bebf91 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6h.gno @@ -0,0 +1,33 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 2; i++ { + x := i + for j := 0; j < 2; j++ { + y := j + f := func() int { + return x + y + } + fns = append(fns, f) + } + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) } }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Go Output: +// 0 +// 1 +// 1 +// 2 + +// Output: +// 0 +// 1 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6h0.gno b/gnovm/tests/files/heap_alloc_forloop6h0.gno new file mode 100644 index 00000000000..0225bd62cf6 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6h0.gno @@ -0,0 +1,27 @@ +package main + +func main() { + var fns []func() int + for i := 0; i < 2; i++ { + for j := 0; j < 2; j++ { + f := func() int { + return i + j + } + fns = append(fns, f) + } + } + for _, fn := range fns { + println(fn()) + } +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { for j := (const (0 int)); j<~VPBlock(1,0)> < (const (2 int)); j<~VPBlock(1,0)>++ { f := func func() (const-type int){ return i<~VPBlock(1,1)> + j<~VPBlock(1,2)> }, j<()~VPBlock(1,0)>>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) } }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 4 +// 4 +// 4 +// 4 diff --git a/gnovm/tests/files/heap_alloc_forloop6i.gno b/gnovm/tests/files/heap_alloc_forloop6i.gno new file mode 100644 index 00000000000..28bb17cbf5f --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop6i.gno @@ -0,0 +1,34 @@ +package main + +func main() { + var fns []func() int + var x int + for i := 0; i < 2; i++ { + x = i + for j := 0; j < 2; j++ { + y := j + f := func() int { + return x + y + } + fns = append(fns, f) + } + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); var x (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x = i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() (const-type int){ return x + y<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) } }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Go Output: +// 1 +// 2 +// 1 +// 2 + +// Output: +// 1 +// 2 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop7.gno b/gnovm/tests/files/heap_alloc_forloop7.gno new file mode 100644 index 00000000000..95fdf42045d --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop7.gno @@ -0,0 +1,28 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 2; i++ { + x := i + f := func() int { + if true { + if true { + return x + } + } + return 0 + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ if (const (true bool)) { if (const (true bool)) { return x<~VPBlock(3,1)> } }; return (const (0 int)) }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_forloop7a.gno b/gnovm/tests/files/heap_alloc_forloop7a.gno new file mode 100644 index 00000000000..59e83022f57 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop7a.gno @@ -0,0 +1,26 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 2; i++ { + x := i + f := func() int { + if true { + return x + } + return 0 + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_forloop8.gno b/gnovm/tests/files/heap_alloc_forloop8.gno new file mode 100644 index 00000000000..7c86fdc5b90 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop8.gno @@ -0,0 +1,25 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 2; i++ { + x := i + f := func() int { + { + return x + } + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ { return x<~VPBlock(2,1)> } }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_forloop8a.gno b/gnovm/tests/files/heap_alloc_forloop8a.gno new file mode 100644 index 00000000000..f0864fa07da --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop8a.gno @@ -0,0 +1,26 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 2; i++ { + x := i + f := func() int { + for i := 0; i < 1; i++ { + x++ + } + return x + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ for i := (const (0 int)); i < (const (1 int)); i++ { x<~VPBlock(2,1)>++ }; return x<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop8b.gno b/gnovm/tests/files/heap_alloc_forloop8b.gno new file mode 100644 index 00000000000..1cd6bf13cc3 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop8b.gno @@ -0,0 +1,28 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 2; i++ { + x := i + s := []int{1, 2} + + f := func() int { + for _, v := range s { + x += v + } + return x + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; s := [](const-type int){(const (1 int)), (const (2 int))}; f := func func() (const-type int){ for _, v := range s<~VPBlock(2,1)> { x<~VPBlock(2,2)> += v }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 3 +// 4 diff --git a/gnovm/tests/files/heap_alloc_forloop8c.gno b/gnovm/tests/files/heap_alloc_forloop8c.gno new file mode 100644 index 00000000000..11aef1683b8 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop8c.gno @@ -0,0 +1,30 @@ +package main + +func main() { + var fns []func() int + + for i := 0; i < 2; i++ { + x := i + y := 1 + f := func() int { + switch y { + case 1: + x += 1 + default: + x += 0 + } + return x + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (1 int)); f := func func() (const-type int){ switch y<~VPBlock(2,1)> { case (const (1 int)): x<~VPBlock(2,2)> += (const (1 int)); default: x<~VPBlock(2,2)> += (const (0 int)) }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop9.gno b/gnovm/tests/files/heap_alloc_forloop9.gno new file mode 100644 index 00000000000..0f1d0b8b23c --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop9.gno @@ -0,0 +1,42 @@ +package main + +import "fmt" + +// recursive closure does not capture +func main() { + var fns []func(int) int + var recursiveFunc func(int) int + + for i := 0; i < 3; i++ { + recursiveFunc = func(num int) int { + x := i + println("value of x: ", x) + if num <= 0 { + return 1 + } + return num * recursiveFunc(num-1) + } + fns = append(fns, recursiveFunc) + } + + for i, r := range fns { + result := r(i) + fmt.Printf("Factorial of %d is: %d\n", i, result) + } +} + +// go 1.22 loop var is not supported for now. + +// Preprocessed: +// file{ package main; import fmt fmt; func main() { var fns []func(.arg_0 (const-type int)) (const-type int); var recursiveFunc func(.arg_0 (const-type int)) (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { recursiveFunc = func func(num (const-type int)) (const-type int){ x := i<~VPBlock(1,3)>; (const (println func(xs ...interface{})()))((const ("value of x: " string)), x); if num <= (const (0 int)) { return (const (1 int)) }; return num * recursiveFunc(num - (const (1 int))) }>; fns = (const (append func(x []func(.arg_0 int)( int),args ...func(.arg_0 int)( int))(res []func(.arg_0 int)( int))))(fns, recursiveFunc) }; for i, r := range fns { result := r(i); fmt.Printf((const ("Factorial of %d is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(result)) } } } + +// Output: +// value of x: 3 +// Factorial of 0 is: 1 +// value of x: 3 +// value of x: 3 +// Factorial of 1 is: 1 +// value of x: 3 +// value of x: 3 +// value of x: 3 +// Factorial of 2 is: 2 diff --git a/gnovm/tests/files/heap_alloc_forloop9_1.gno b/gnovm/tests/files/heap_alloc_forloop9_1.gno new file mode 100644 index 00000000000..5e3b9af74f6 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop9_1.gno @@ -0,0 +1,25 @@ +package main + +func Search(n int, f func(int) bool) int { + f(1) + return 0 +} + +// TODO: identify this pattern, optimize. +func main() { + for x := 0; x < 2; x++ { + count := 0 + println(" first: count: ", count) + Search(1, func(i int) bool { count++; return i >= x }) + println("second: count: ", count) + } +} + +// Preprocessed: +// file{ package main; func Search(n (const-type int), f func(.arg_0 (const-type int)) (const-type bool)) (const-type int) { f((const (1 int))); return (const (0 int)) }; func main() { for x := (const (0 int)); x<~VPBlock(1,0)> < (const (2 int)); x<~VPBlock(1,0)>++ { count := (const (0 int)); (const (println func(xs ...interface{})()))((const (" first: count: " string)), count<~VPBlock(1,1)>); Search((const (1 int)), func func(i (const-type int)) (const-type bool){ count<~VPBlock(1,2)>++; return (const-type bool)(i >= x<~VPBlock(1,3)>) }, x<()~VPBlock(1,0)>>); (const (println func(xs ...interface{})()))((const ("second: count: " string)), count<~VPBlock(1,1)>) } } } + +// Output: +// first: count: 0 +// second: count: 1 +// first: count: 0 +// second: count: 1 diff --git a/gnovm/tests/files/heap_alloc_forloop9_2.gno b/gnovm/tests/files/heap_alloc_forloop9_2.gno new file mode 100644 index 00000000000..6b1ebdbb7e9 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop9_2.gno @@ -0,0 +1,36 @@ +package main + +func main() { + var fns []func() int + + println("start for loop") + for i := 0; i < 2; i++ { + defer func() { + println("defer") + for _, fn := range fns { + println(fn()) + } + }() + + x := i + f := func() int { + return x + } + + fns = append(fns, f) + } + println("end for loop") +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); (const (println func(xs ...interface{})()))((const ("start for loop" string))); for i := (const (0 int)); i < (const (2 int)); i++ { defer func func(){ (const (println func(xs ...interface{})()))((const ("defer" string))); for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } }(); x := i; f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; (const (println func(xs ...interface{})()))((const ("end for loop" string))) } } + +// Output: +// start for loop +// end for loop +// defer +// 0 +// 1 +// defer +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_forloop9b.gno b/gnovm/tests/files/heap_alloc_forloop9b.gno new file mode 100644 index 00000000000..03e84fcd2b2 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop9b.gno @@ -0,0 +1,28 @@ +package main + +func main() { + var y int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + for i := 0; i < 2; i++ { + for j := 0; j < 2; j++ { + x := y + f = append(f, func() { println(x) }) + y++ + } + } +} + +// Preprocessed: +// file{ package main; func main() { var y (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); for i := (const (0 int)); i < (const (2 int)); i++ { for j := (const (0 int)); j < (const (2 int)); j++ { x := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++ } } } } + +// Output: +// 0 +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/heap_alloc_gotoloop0.gno b/gnovm/tests/files/heap_alloc_gotoloop0.gno new file mode 100644 index 00000000000..d13baedf7c4 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop0.gno @@ -0,0 +1,28 @@ +package main + +func main() { + var counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + // this is actually an implicit for loop +LABEL_1: + if counter == 2 { + return + } + x := counter + f = append(f, func() { println(x) }) + counter++ + goto LABEL_1 +} + +// Preprocessed: +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); if counter == (const (2 int)) { return }; x := counter; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); counter++; goto LABEL_1<0,3> } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop1.gno b/gnovm/tests/files/heap_alloc_gotoloop1.gno new file mode 100644 index 00000000000..ea26952e0a4 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop1.gno @@ -0,0 +1,30 @@ +package main + +func main() { + c := 0 +loop: + i := 1 + println(i) + c += 1 + if c < 10 { + goto loop + } +} + +// This does not make 'i' NameExprTypeHeapDefine, +// because it is not actually used in a &ref or closure context. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); i := (const (1 int)); (const (println func(xs ...interface{})()))(i); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,1> } } } + +// Output: +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop2.gno b/gnovm/tests/files/heap_alloc_gotoloop2.gno new file mode 100644 index 00000000000..e7b2917a8ff --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop2.gno @@ -0,0 +1,37 @@ +package main + +func main() { + c := 0 + closures := []func(){} +loop: + i := c + closures = append(closures, func() { + println(i) + }) + c += 1 + if c < 10 { + goto loop + } + + for _, cl := range closures { + cl() + } +} + +// This does make 'i' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of i and i<()~...>. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; i := c; closures = (const (append func(x []func()(),args ...func()())(res []func()())))(closures, func func(){ (const (println func(xs ...interface{})()))(i<~VPBlock(1,0)>) }>); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, cl := range closures { cl() } } } + +// Output: +// 0 +// 1 +// 2 +// 3 +// 4 +// 5 +// 6 +// 7 +// 8 +// 9 diff --git a/gnovm/tests/files/heap_alloc_gotoloop3.gno b/gnovm/tests/files/heap_alloc_gotoloop3.gno new file mode 100644 index 00000000000..a248e8aa0bc --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop3.gno @@ -0,0 +1,34 @@ +package main + +func main() { + c := 0 + refs := []*int{} +loop: + i := c + refs = append(refs, &i) + c += 1 + if c < 10 { + goto loop + } + for _, ref := range refs { + println(*ref) + } +} + +// This does make 'i' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of i and i<~...>. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; i := c; refs = (const (append func(x []*int,args ...*int)(res []*int)))(refs, &(i<~VPBlock(1,2)>)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(xs ...interface{})()))(*(ref)) } } } + +// Output: +// 0 +// 1 +// 2 +// 3 +// 4 +// 5 +// 6 +// 7 +// 8 +// 9 diff --git a/gnovm/tests/files/heap_alloc_gotoloop4.gno b/gnovm/tests/files/heap_alloc_gotoloop4.gno new file mode 100644 index 00000000000..062d832ac16 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop4.gno @@ -0,0 +1,34 @@ +package main + +func main() { + c := 0 + refs := []*int{} +loop: + var i int = c + refs = append(refs, &i) + c += 1 + if c < 10 { + goto loop + } + for _, ref := range refs { + println(*ref) + } +} + +// This does make 'i' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of i and i<~...>. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i (const-type int) = c; refs = (const (append func(x []*int,args ...*int)(res []*int)))(refs, &(i<~VPBlock(1,2)>)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(xs ...interface{})()))(*(ref)) } } } + +// Output: +// 0 +// 1 +// 2 +// 3 +// 4 +// 5 +// 6 +// 7 +// 8 +// 9 diff --git a/gnovm/tests/files/heap_alloc_gotoloop5.gno b/gnovm/tests/files/heap_alloc_gotoloop5.gno new file mode 100644 index 00000000000..fb7a82228f1 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop5.gno @@ -0,0 +1,39 @@ +package main + +func main() { + c := 0 + refs := []*int{} +loop: + i, j := c, 2 + refs = append(refs, &i) + i += 1 + j += 1 + c += 1 + if c < 10 { + goto loop + } + for _, ref := range refs { + println(*ref) + } + if false { + println(j) // dummy usage + } +} + +// This does make 'i' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of i and i<~...>. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; i, j := c, (const (2 int)); refs = (const (append func(x []*int,args ...*int)(res []*int)))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(xs ...interface{})()))(*(ref)) }; if (const (false bool)) { (const (println func(xs ...interface{})()))(j) } } } + +// Output: +// 1 +// 2 +// 3 +// 4 +// 5 +// 6 +// 7 +// 8 +// 9 +// 10 diff --git a/gnovm/tests/files/heap_alloc_gotoloop6.gno b/gnovm/tests/files/heap_alloc_gotoloop6.gno new file mode 100644 index 00000000000..d2efbb85df2 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop6.gno @@ -0,0 +1,39 @@ +package main + +func main() { + c := 0 + refs := []*int{} +loop: + var i, j int = c, 2 + refs = append(refs, &i) + i += 1 + j += 1 + c += 1 + if c < 10 { + goto loop + } + for _, ref := range refs { + println(*ref) + } + if false { + println(j) // dummy usage + } +} + +// This does make 'i' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of i and i<~...>. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i, j (const-type int) = c, (const (2 int)); refs = (const (append func(x []*int,args ...*int)(res []*int)))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(xs ...interface{})()))(*(ref)) }; if (const (false bool)) { (const (println func(xs ...interface{})()))(j) } } } + +// Output: +// 1 +// 2 +// 3 +// 4 +// 5 +// 6 +// 7 +// 8 +// 9 +// 10 diff --git a/gnovm/tests/files/heap_alloc_gotoloop7.gno b/gnovm/tests/files/heap_alloc_gotoloop7.gno new file mode 100644 index 00000000000..457fdb74a01 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop7.gno @@ -0,0 +1,48 @@ +package main + +func main() { + c := 0 + refs := []*int{} +loop: + var i, j int = c, 2 + refs = append(refs, &i) + i += 1 + j += 1 + c += 1 + thing := func() { + i := 2 // new i + j := 3 // new j + println(i) + println(j) + } + if c < 10 { + goto loop + } + for _, ref := range refs { + println(*ref) + } + if false { + println(j) // dummy usage + } + if false { + thing() // dummy usage + } +} + +// This does make 'i' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of i and i<~...>. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i, j (const-type int) = c, (const (2 int)); refs = (const (append func(x []*int,args ...*int)(res []*int)))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); thing := func func(){ i := (const (2 int)); j := (const (3 int)); (const (println func(xs ...interface{})()))(i); (const (println func(xs ...interface{})()))(j) }; if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(xs ...interface{})()))(*(ref)) }; if (const (false bool)) { (const (println func(xs ...interface{})()))(j) }; if (const (false bool)) { thing() } } } + +// Output: +// 1 +// 2 +// 3 +// 4 +// 5 +// 6 +// 7 +// 8 +// 9 +// 10 diff --git a/gnovm/tests/files/heap_alloc_gotoloop8.gno b/gnovm/tests/files/heap_alloc_gotoloop8.gno new file mode 100644 index 00000000000..f3421048d41 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop8.gno @@ -0,0 +1,37 @@ +package main + +func main() { + c := 0 + closures := []func(){} + goto loop1 +loop1: // not a loop + i := 1 +loop2: + closures = append(closures, func() { + println(i) + }) + c += 1 + if c < 10 { + goto loop2 + } + for _, cl := range closures { + cl() + } +} + +// This one doesn't because the goto stmt doesn't go back far enough. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; goto loop1<0,3>; i := (const (1 int)); closures = (const (append func(x []func()(),args ...func()())(res []func()())))(closures, func func(){ (const (println func(xs ...interface{})()))(i) }); c += (const (1 int)); if c < (const (10 int)) { goto loop2<1,4> }; for _, cl := range closures { cl() } } } + +// Output: +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9.gno b/gnovm/tests/files/heap_alloc_gotoloop9.gno new file mode 100644 index 00000000000..38204652216 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9.gno @@ -0,0 +1,35 @@ +package main + +func main() { + c := 0 + closures := []func(){} + i := 1 +loop2: + closures = append(closures, func() { + println(i) + }) + c += 1 + if c < 10 { + goto loop2 + } + for _, cl := range closures { + cl() + } +} + +// This one doesn't because the goto stmt doesn't go back far enough. + +// Preprocessed: +// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; i := (const (1 int)); closures = (const (append func(x []func()(),args ...func()())(res []func()())))(closures, func func(){ (const (println func(xs ...interface{})()))(i) }); c += (const (1 int)); if c < (const (10 int)) { goto loop2<1,3> }; for _, cl := range closures { cl() } } } + +// Output: +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_10.gno b/gnovm/tests/files/heap_alloc_gotoloop9_10.gno new file mode 100644 index 00000000000..bb8a2bad3ef --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_10.gno @@ -0,0 +1,64 @@ +package main + +import "fmt" + +var s1 []*int +var s2 []*int + +// intersection loop +func main() { + defer func() { + for i, v := range s1 { + fmt.Printf("s1[%d] is %d\n", i, *v) + } + for i, v := range s2 { + fmt.Printf("s2[%d] is %d\n", i, *v) + } + }() + + // counter for loop + var c1, c2 int + +LOOP_1: + x := c1 + s1 = append(s1, &x) + println("loop_1", c1) + c1++ + +LOOP_2: + y := c2 + s2 = append(s2, &y) + println("loop_2", c2) + c2++ + + if c1 < 3 { + goto LOOP_1 + } + + if c2 < 6 { + goto LOOP_2 + } +} + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); var s2 []*((const-type int)); func main() { defer func func(){ for i, v := range s1 { fmt.Printf((const ("s1[%d] is %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(v))) }; for i, v := range s2 { fmt.Printf((const ("s2[%d] is %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(v))) } }(); var c1, c2 (const-type int); x := c1; s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(x<~VPBlock(1,2)>)); (const (println func(xs ...interface{})()))((const ("loop_1" string)), c1); c1++; y := c2; s2 = (const (append func(x []*int,args ...*int)(res []*int)))(s2, &(y<~VPBlock(1,3)>)); (const (println func(xs ...interface{})()))((const ("loop_2" string)), c2); c2++; if c1 < (const (3 int)) { goto LOOP_1<1,2> }; if c2 < (const (6 int)) { goto LOOP_2<1,6> } } } + +// Output: +// loop_1 0 +// loop_2 0 +// loop_1 1 +// loop_2 1 +// loop_1 2 +// loop_2 2 +// loop_2 3 +// loop_2 4 +// loop_2 5 +// s1[0] is 0 +// s1[1] is 1 +// s1[2] is 2 +// s2[0] is 0 +// s2[1] is 1 +// s2[2] is 2 +// s2[3] is 3 +// s2[4] is 4 +// s2[5] is 5 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_11.gno b/gnovm/tests/files/heap_alloc_gotoloop9_11.gno new file mode 100644 index 00000000000..839612704a8 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_11.gno @@ -0,0 +1,29 @@ +package main + +func main() { + var y, counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + // this is actually an implicit for loop +LABEL_1: + if counter == 2 { + return + } + var _, x = 0, y + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); if counter == (const (2 int)) { return }; var _, x = (const (0 int)), y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,3> } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_12.gno b/gnovm/tests/files/heap_alloc_gotoloop9_12.gno new file mode 100644 index 00000000000..4d024a58673 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_12.gno @@ -0,0 +1,56 @@ +package main + +import "fmt" + +func main() { + counter0 := 0 + counter1 := 0 + + y := 0 + + var fs []func() + + defer func() { + for _, ff := range fs { + ff() + } + }() + +LOOP_START: + if counter0 < 2 { + counter1 = 0 + fmt.Printf("Outer loop start: counter0=%d\n", counter0) + + NESTED_LOOP_START: + if counter1 < 2 { + fmt.Printf(" Nested loop: counter1=%d\n", counter1) + counter1++ + goto NESTED_LOOP_START + } + + x := y + fs = append(fs, func() { println(x) }) + + fmt.Println("Exiting nested loop") + counter0++ + y++ + goto LOOP_START + } else { + return + } +} + +// Preprocessed: +// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs { ff() } }(); if counter0 < (const (2 int)) { counter1 = (const (0 int)); fmt.Printf((const ("Outer loop start: counter0=%d\n" string)), (const-type gonative{interface {}})(counter0)); if counter1 < (const (2 int)) { fmt.Printf((const (" Nested loop: counter1=%d\n" string)), (const-type gonative{interface {}})(counter1)); counter1++; goto NESTED_LOOP_START<1,2> }; x := y; fs = (const (append func(x []func()(),args ...func()())(res []func()())))(fs, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); fmt.Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } + +// Output: +// Outer loop start: counter0=0 +// Nested loop: counter1=0 +// Nested loop: counter1=1 +// Exiting nested loop +// Outer loop start: counter0=1 +// Nested loop: counter1=0 +// Nested loop: counter1=1 +// Exiting nested loop +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_13.gno b/gnovm/tests/files/heap_alloc_gotoloop9_13.gno new file mode 100644 index 00000000000..7c7b6777223 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_13.gno @@ -0,0 +1,41 @@ +package main + +func main() { + var y, counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + +LABEL_1: + x := y + if counter == 2 { + counter = 0 + goto LABEL_2 + } + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 + +LABEL_2: + if counter == 2 { + return + } + z := y + f = append(f, func() { println(z) }) + y++ + counter++ + goto LABEL_2 +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); x := y; if counter == (const (2 int)) { counter = (const (0 int)); goto LABEL_2<1,9> }; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,3>; if counter == (const (2 int)) { return }; z := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,9> } } + +// Output: +// 0 +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_14.gno b/gnovm/tests/files/heap_alloc_gotoloop9_14.gno new file mode 100644 index 00000000000..f92b31eb7de --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_14.gno @@ -0,0 +1,43 @@ +package main + +func main() { + var y, counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + { + LABEL_1: + x := y + if counter == 2 { + counter = 0 + goto LABEL_2 + } + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 + } + +LABEL_2: + if counter == 2 { + return + } + z := y + f = append(f, func() { println(z) }) + y++ + counter++ + goto LABEL_2 +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); { x := y; if counter == (const (2 int)) { counter = (const (0 int)); goto LABEL_2<2,4> }; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> }; if counter == (const (2 int)) { return }; z := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,4> } } + +// Output: +// 0 +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_15.gno b/gnovm/tests/files/heap_alloc_gotoloop9_15.gno new file mode 100644 index 00000000000..d774af55eb6 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_15.gno @@ -0,0 +1,48 @@ +package main + +var y, counter int +var f []func() + +func main() { + defer func() { + for _, ff := range f { // XXX, why defer on this not work + ff() + } + }() +LABEL_1: + x := y + if counter == 2 { + counter = 0 + bar() + return + } + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 +} + +func bar() { + println("---bar---") +LABEL_2: + if counter == 2 { + println("---end---") + return + } + z := y + f = append(f, func() { println(z) }) + y++ + counter++ + goto LABEL_2 +} + +// Preprocessed: +// file{ package main; var y, counter (const-type int); var f []func(); func main() { defer func func(){ for _, ff := range f { ff() } }(); x := y; if counter == (const (2 int)) { counter = (const (0 int)); bar(); return }; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,1> }; func bar() { (const (println func(xs ...interface{})()))((const ("---bar---" string))); if counter == (const (2 int)) { (const (println func(xs ...interface{})()))((const ("---end---" string))); return }; z := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,1> } } + +// Output: +// ---bar--- +// ---end--- +// 0 +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno b/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno new file mode 100644 index 00000000000..2d9de02ecc3 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno @@ -0,0 +1,46 @@ +package main + +var y, counter int +var f []func() + +func main() { +LABEL_1: + x := y + if counter == 2 { + counter = 0 + bar() + for _, ff := range f { // XXX, why defer on this not work + ff() + } + return + } + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 +} + +func bar() { + println("---bar---") +LABEL_2: + if counter == 2 { + println("---end---") + return + } + z := y + f = append(f, func() { println(z) }) + y++ + counter++ + goto LABEL_2 +} + +// Preprocessed: +// file{ package main; var y, counter (const-type int); var f []func(); func main() { x := y; if counter == (const (2 int)) { counter = (const (0 int)); bar(); for _, ff := range f { ff() }; return }; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> }; func bar() { (const (println func(xs ...interface{})()))((const ("---bar---" string))); if counter == (const (2 int)) { (const (println func(xs ...interface{})()))((const ("---end---" string))); return }; z := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,1> } } + +// Output: +// ---bar--- +// ---end--- +// 0 +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_16.gno b/gnovm/tests/files/heap_alloc_gotoloop9_16.gno new file mode 100644 index 00000000000..8971b04aee6 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_16.gno @@ -0,0 +1,58 @@ +package main + +import "fmt" + +func main() { + counter0 := 0 + counter1 := 0 + + y := 0 + + var fs []func() + + defer func() { + for _, ff := range fs { + ff() + } + }() + +LOOP_START: + if counter0 < 2 { + x := y + counter1 = 0 + fmt.Printf("Outer loop start: counter0=%d\n", counter0) + + NESTED_LOOP_START: + if counter1 < 2 { + fmt.Printf(" Nested loop: counter1=%d\n", counter1) + fs = append(fs, func() { println(x) }) + + counter1++ + goto NESTED_LOOP_START + } + + fmt.Println("Exiting nested loop") + counter0++ + y++ + goto LOOP_START + } else { + return + } +} + +// Preprocessed: +// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs { ff() } }(); if counter0 < (const (2 int)) { x := y; counter1 = (const (0 int)); fmt.Printf((const ("Outer loop start: counter0=%d\n" string)), (const-type gonative{interface {}})(counter0)); if counter1 < (const (2 int)) { fmt.Printf((const (" Nested loop: counter1=%d\n" string)), (const-type gonative{interface {}})(counter1)); fs = (const (append func(x []func()(),args ...func()())(res []func()())))(fs, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); counter1++; goto NESTED_LOOP_START<1,3> }; fmt.Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } + +// Output: +// Outer loop start: counter0=0 +// Nested loop: counter1=0 +// Nested loop: counter1=1 +// Exiting nested loop +// Outer loop start: counter0=1 +// Nested loop: counter1=0 +// Nested loop: counter1=1 +// Exiting nested loop +// 0 +// 0 +// 1 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_17.gno b/gnovm/tests/files/heap_alloc_gotoloop9_17.gno new file mode 100644 index 00000000000..9e5073c1bfe --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_17.gno @@ -0,0 +1,58 @@ +package main + +import "fmt" + +func main() { + counter0 := 0 + counter1 := 0 + + y := 0 + + var fs []func() + + defer func() { + for _, ff := range fs { + ff() + } + }() + +LOOP_START: + x := y + if counter0 < 2 { + counter1 = 0 + fmt.Printf("Outer loop start: counter0=%d\n", counter0) + + NESTED_LOOP_START: + if counter1 < 2 { + fmt.Printf(" Nested loop: counter1=%d\n", counter1) + fs = append(fs, func() { println(x) }) + + counter1++ + goto NESTED_LOOP_START + } + + fmt.Println("Exiting nested loop") + counter0++ + y++ + goto LOOP_START + } else { + return + } +} + +// Preprocessed: +// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs { ff() } }(); x := y; if counter0 < (const (2 int)) { counter1 = (const (0 int)); fmt.Printf((const ("Outer loop start: counter0=%d\n" string)), (const-type gonative{interface {}})(counter0)); if counter1 < (const (2 int)) { fmt.Printf((const (" Nested loop: counter1=%d\n" string)), (const-type gonative{interface {}})(counter1)); fs = (const (append func(x []func()(),args ...func()())(res []func()())))(fs, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); counter1++; goto NESTED_LOOP_START<1,2> }; fmt.Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } + +// Output: +// Outer loop start: counter0=0 +// Nested loop: counter1=0 +// Nested loop: counter1=1 +// Exiting nested loop +// Outer loop start: counter0=1 +// Nested loop: counter1=0 +// Nested loop: counter1=1 +// Exiting nested loop +// 0 +// 0 +// 1 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_18.gno b/gnovm/tests/files/heap_alloc_gotoloop9_18.gno new file mode 100644 index 00000000000..1578eb5897f --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_18.gno @@ -0,0 +1,30 @@ +package main + +func main() { + var y, counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + { + LABEL_1: + if counter == 2 { + return + } + x := y + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 + } +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); { if counter == (const (2 int)) { return }; x := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> } } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_19.gno b/gnovm/tests/files/heap_alloc_gotoloop9_19.gno new file mode 100644 index 00000000000..fb1b995372e --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_19.gno @@ -0,0 +1,30 @@ +package main + +func main() { + var y, counter int + var f []func() func() int + defer func() { + for _, ff := range f { + println(ff()()) + } + }() + +LABEL_1: + if counter == 2 { + return + } + x := y + f = append(f, func() func() int { + return func() int { return x } + }) + y++ + counter++ + goto LABEL_1 +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func() func() (const-type int); defer func func(){ for _, ff := range f { (const (println func(xs ...interface{})()))(ff()()) } }(); if counter == (const (2 int)) { return }; x := y; f = (const (append func(x []func()( func()( int)),args ...func()( func()( int)))(res []func()( func()( int)))))(f, func func() func() (const-type int){ return func func() (const-type int){ return x<~VPBlock(2,1)> } }>); y++; counter++; goto LABEL_1<0,3> } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_20.gno b/gnovm/tests/files/heap_alloc_gotoloop9_20.gno new file mode 100644 index 00000000000..04896b425a5 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_20.gno @@ -0,0 +1,32 @@ +package main + +func main() { + var y, counter int + var f []func() (int, func() int) + defer func() { + for _, ff := range f { + n, f := ff() + println(n + f()) + } + }() + +LABEL_1: + if counter == 2 { + return + } + x := y + z := y + f = append(f, func() (int, func() int) { + return z, func() int { return x } + }) + y++ + counter++ + goto LABEL_1 +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func() (const-type int), func() (const-type int); defer func func(){ for _, ff := range f { n, f := ff(); (const (println func(xs ...interface{})()))(n + f()) } }(); if counter == (const (2 int)) { return }; x := y; z := y; f = (const (append func(x []func()( int, func()( int)),args ...func()( int, func()( int)))(res []func()( int, func()( int)))))(f, func func() (const-type int), func() (const-type int){ return z<~VPBlock(1,2)>, func func() (const-type int){ return x<~VPBlock(2,3)> } }, x<()~VPBlock(1,3)>>); y++; counter++; goto LABEL_1<0,3> } } + +// Output: +// 0 +// 2 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_21.gno b/gnovm/tests/files/heap_alloc_gotoloop9_21.gno new file mode 100644 index 00000000000..fa27f3376e0 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_21.gno @@ -0,0 +1,31 @@ +package main + +func main() { + var counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + f1 := func() { + LABEL_1: + if counter == 2 { + return + } + x := counter + f = append(f, func() { println(x) }) + counter++ + goto LABEL_1 + } + + f1() +} + +// Preprocessed: +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); f1 := func func(){ if counter == (const (2 int)) { return }; x := counter; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); counter++; goto LABEL_1<0,0> }; f1() } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno b/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno new file mode 100644 index 00000000000..48364ed4075 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno @@ -0,0 +1,33 @@ +package main + +func main() { + var counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + f1 := func() { + LABEL_1: + if counter == 2 { + return + } + x := counter + func() { + f = append(f, func() { println(x) }) + }() + counter++ + goto LABEL_1 + } + + f1() +} + +// Preprocessed: +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); f1 := func func(){ if counter == (const (2 int)) { return }; x := counter; func func(){ f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(2,0)>) }) }>(); counter++; goto LABEL_1<0,0> }; f1() } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno b/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno new file mode 100644 index 00000000000..8758608a5e6 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno @@ -0,0 +1,34 @@ +package main + +func main() { + var counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + f1 := func() { + LABEL_1: + if counter == 2 { + return + } + + func() { + x := counter + f = append(f, func() { println(x) }) + }() + counter++ + goto LABEL_1 + } + + f1() +} + +// Preprocessed: +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); f1 := func func(){ if counter == (const (2 int)) { return }; func func(){ x := counter; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x) }) }(); counter++; goto LABEL_1<0,0> }; f1() } } + +// Output: +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_22.gno b/gnovm/tests/files/heap_alloc_gotoloop9_22.gno new file mode 100644 index 00000000000..cd283345869 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_gotoloop9_22.gno @@ -0,0 +1,33 @@ +package main + +func main() { + var y, counter int + var f []func() + defer func() { + for _, ff := range f { + ff() + } + }() + + for i := 0; i < 2; i++ { + counter = 0 + LABEL_1: + if counter == 2 { + continue + } + x := y + f = append(f, func() { println(x) }) + y++ + counter++ + goto LABEL_1 + } +} + +// Preprocessed: +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); for i := (const (0 int)); i < (const (2 int)); i++ { counter = (const (0 int)); if counter == (const (2 int)) { continue }; x := y; f = (const (append func(x []func()(),args ...func()())(res []func()())))(f, func func(){ (const (println func(xs ...interface{})()))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,1> } } } + +// Output: +// 0 +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/heap_alloc_range1.gno b/gnovm/tests/files/heap_alloc_range1.gno new file mode 100644 index 00000000000..34520729a06 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range1.gno @@ -0,0 +1,30 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + s := []int{0, 1, 2} + for i, _ := range s { + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); s := [](const-type int){(const (0 int)), (const (1 int)), (const (2 int))}; for i, _ := range s { s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(i)) } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 2 +// s1[1] is: 2 +// s1[2] is: 2 diff --git a/gnovm/tests/files/heap_alloc_range2.gno b/gnovm/tests/files/heap_alloc_range2.gno new file mode 100644 index 00000000000..34b7cc527af --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range2.gno @@ -0,0 +1,30 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + s := []int{0, 1, 2} + for _, v := range s { + s1 = append(s1, &v) + } +} + +func main() { + forLoopRef() +} + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), (const-type gonative{interface {}})(i), (const-type gonative{interface {}})(*(e))) } }(); s := [](const-type int){(const (0 int)), (const (1 int)), (const (2 int))}; for _, v := range s { s1 = (const (append func(x []*int,args ...*int)(res []*int)))(s1, &(v)) } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 2 +// s1[1] is: 2 +// s1[2] is: 2 diff --git a/gnovm/tests/files/heap_alloc_range3.gno b/gnovm/tests/files/heap_alloc_range3.gno new file mode 100644 index 00000000000..032d0cf8b6d --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range3.gno @@ -0,0 +1,23 @@ +package main + +func main() { + s := []int{1, 2} + + f := func() { + for i, v := range s { + println(i) + println(v) + } + } + + f() +} + +// Preprocessed: +// file{ package main; func main() { s := [](const-type int){(const (1 int)), (const (2 int))}; f := func func(){ for i, v := range s { (const (println func(xs ...interface{})()))(i); (const (println func(xs ...interface{})()))(v) } }; f() } } + +// Output: +// 0 +// 1 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_range4.gno b/gnovm/tests/files/heap_alloc_range4.gno new file mode 100644 index 00000000000..2418184caca --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range4.gno @@ -0,0 +1,24 @@ +package main + +func main() { + var fns []func() int + s := []int{1, 2, 3} + for i, _ := range s { + x := i + f := func() int { + return x + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); s := [](const-type int){(const (1 int)), (const (2 int)), (const (3 int))}; for i, _ := range s { x := i; f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_range4a.gno b/gnovm/tests/files/heap_alloc_range4a.gno new file mode 100644 index 00000000000..229d59d6011 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range4a.gno @@ -0,0 +1,26 @@ +package main + +func main() { + var fns []func() int + m := map[string]int{"a": 1, "b": 2} + for _, v := range m { + x := v + f := func() int { + if true { + return x + } + return 0 + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { x := v; f := func func() (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_range4a1.gno b/gnovm/tests/files/heap_alloc_range4a1.gno new file mode 100644 index 00000000000..7b126b0e530 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range4a1.gno @@ -0,0 +1,22 @@ +package main + +func main() { + var fns []func() int + m := map[string]int{"a": 1, "b": 2} + for _, v := range m { + f := func() int { + return v + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { f := func func() (const-type int){ return v }; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 2 +// 2 diff --git a/gnovm/tests/files/heap_alloc_range4a2.gno b/gnovm/tests/files/heap_alloc_range4a2.gno new file mode 100644 index 00000000000..c54450f4619 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range4a2.gno @@ -0,0 +1,32 @@ +package main + +func main() { + var fns []func() int + y := 0 + m := map[string]int{"a": 1, "b": 2} + for _, v := range m { + x := v + f := func() int { + switch y { + case 0: + if true { + return x + } + default: + return 0 + } + return 0 + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); y := (const (0 int)); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { x := v; f := func func() (const-type int){ switch y { case (const (0 int)): if (const (true bool)) { return x<~VPBlock(3,1)> }; default: return (const (0 int)) }; return (const (0 int)) }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_range4b.gno b/gnovm/tests/files/heap_alloc_range4b.gno new file mode 100644 index 00000000000..b4a380b361b --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range4b.gno @@ -0,0 +1,26 @@ +package main + +func main() { + var fns []func() int + s := "hello" + for i, _ := range s { + x := i + f := func() int { + return x + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); s := (const ("hello" string)); for i, _ := range s { x := i; f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 0 +// 1 +// 2 +// 3 +// 4 diff --git a/gnovm/tests/files/heap_alloc_range4b1.gno b/gnovm/tests/files/heap_alloc_range4b1.gno new file mode 100644 index 00000000000..24dd99ea98f --- /dev/null +++ b/gnovm/tests/files/heap_alloc_range4b1.gno @@ -0,0 +1,25 @@ +package main + +func main() { + var fns []func() int + s := "hello" + for i, _ := range s { + f := func() int { + return i + } + fns = append(fns, f) + } + for _, fn := range fns { + println(fn()) + } +} + +// Preprocessed: +// file{ package main; func main() { var fns []func() (const-type int); s := (const ("hello" string)); for i, _ := range s { f := func func() (const-type int){ return i }; fns = (const (append func(x []func()( int),args ...func()( int))(res []func()( int))))(fns, f) }; for _, fn := range fns { (const (println func(xs ...interface{})()))(fn()) } } } + +// Output: +// 4 +// 4 +// 4 +// 4 +// 4 diff --git a/gnovm/tests/files/import6.gno b/gnovm/tests/files/import6.gno index 6909e1ad923..f3cd9930eb5 100644 --- a/gnovm/tests/files/import6.gno +++ b/gnovm/tests/files/import6.gno @@ -7,4 +7,4 @@ func main() { } // Error: -// github.com/gnolang/gno/_test/c2/c2.gno:3:1: import cycle detected: "github.com/gnolang/gno/_test/c1" (through [github.com/gnolang/gno/_test/c1 github.com/gnolang/gno/_test/c2]) +// github.com/gnolang/gno/_test/c2/c2.gno:3:8: import cycle detected: "github.com/gnolang/gno/_test/c1" (through [github.com/gnolang/gno/_test/c1 github.com/gnolang/gno/_test/c2]) diff --git a/gnovm/tests/files/recursive1.gno b/gnovm/tests/files/recursive1.gno index 8279e247d84..cd86d351dec 100644 --- a/gnovm/tests/files/recursive1.gno +++ b/gnovm/tests/files/recursive1.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/recursive1.gno:1:1: invalid recursive type: S -> S +// main/files/recursive1.gno:3:6: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive1c.gno b/gnovm/tests/files/recursive1c.gno index 7797f375027..36237b039c0 100644 --- a/gnovm/tests/files/recursive1c.gno +++ b/gnovm/tests/files/recursive1c.gno @@ -14,4 +14,4 @@ func main() { } // Error: -// main/files/recursive1c.gno:1:1: invalid recursive type: S -> S +// main/files/recursive1c.gno:5:6: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive1d.gno b/gnovm/tests/files/recursive1d.gno index 22bf172b5ac..11c48bed3eb 100644 --- a/gnovm/tests/files/recursive1d.gno +++ b/gnovm/tests/files/recursive1d.gno @@ -14,4 +14,4 @@ func main() { } // Error: -// main/files/recursive1d.gno:1:1: invalid recursive type: S -> S +// main/files/recursive1d.gno:5:6: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive1f.gno b/gnovm/tests/files/recursive1f.gno index 81fe2a5699c..7c6bc8f52fe 100644 --- a/gnovm/tests/files/recursive1f.gno +++ b/gnovm/tests/files/recursive1f.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/recursive1f.gno:3:1: invalid recursive type: S -> S +// main/files/recursive1f.gno:4:7: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive2.gno b/gnovm/tests/files/recursive2.gno index 4ed86f03d58..f2382d7ce1a 100644 --- a/gnovm/tests/files/recursive2.gno +++ b/gnovm/tests/files/recursive2.gno @@ -18,4 +18,4 @@ func main() { } // Error: -// main/files/recursive2.gno:1:1: invalid recursive type: A -> B -> C -> A +// main/files/recursive2.gno:3:6: invalid recursive type: A -> B -> C -> A diff --git a/gnovm/tests/files/recursive2c.gno b/gnovm/tests/files/recursive2c.gno index 3b5c27ed8ea..d6068fba1bc 100644 --- a/gnovm/tests/files/recursive2c.gno +++ b/gnovm/tests/files/recursive2c.gno @@ -18,4 +18,4 @@ func main() { } // Error: -// main/files/recursive2c.gno:3:1: name B not defined in fileset with files [files/recursive2c.gno] +// main/files/recursive2c.gno:4:7: name B not defined in fileset with files [files/recursive2c.gno] diff --git a/gnovm/tests/files/recursive4a.gno b/gnovm/tests/files/recursive4a.gno index 8b4d13b4785..3d2b4e33590 100644 --- a/gnovm/tests/files/recursive4a.gno +++ b/gnovm/tests/files/recursive4a.gno @@ -6,4 +6,4 @@ func main() { } // Error: -// main/files/recursive4a.gno:1:1: invalid recursive type: time -> time +// main/files/recursive4a.gno:3:6: invalid recursive type: time -> time diff --git a/gnovm/tests/files/recursive5.gno b/gnovm/tests/files/recursive5.gno index 1c2fbd89fb8..1498926f305 100644 --- a/gnovm/tests/files/recursive5.gno +++ b/gnovm/tests/files/recursive5.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/recursive5.gno:1:1: invalid recursive type: S -> S +// main/files/recursive5.gno:3:6: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive6a.gno b/gnovm/tests/files/recursive6a.gno index 8123fc626a5..a0791aca7f5 100644 --- a/gnovm/tests/files/recursive6a.gno +++ b/gnovm/tests/files/recursive6a.gno @@ -9,4 +9,4 @@ func main() { } // Error: -// main/files/recursive6a.gno:1:1: invalid recursive type: SelfReferencing -> SelfReferencing +// main/files/recursive6a.gno:3:6: invalid recursive type: SelfReferencing -> SelfReferencing diff --git a/gnovm/tests/files/recursive7a.gno b/gnovm/tests/files/recursive7a.gno index b3c57516f13..b27a3a01324 100644 --- a/gnovm/tests/files/recursive7a.gno +++ b/gnovm/tests/files/recursive7a.gno @@ -5,4 +5,4 @@ type S [2]S func main() {} // Error: -// main/files/recursive7a.gno:1:1: invalid recursive type: S -> S +// main/files/recursive7a.gno:3:6: invalid recursive type: S -> S diff --git a/gnovm/tests/files/recursive8.gno b/gnovm/tests/files/recursive8.gno index 1f9325ae35c..afd5b44fcc6 100644 --- a/gnovm/tests/files/recursive8.gno +++ b/gnovm/tests/files/recursive8.gno @@ -5,4 +5,4 @@ type Int Int func main() {} // Error: -// main/files/recursive8.gno:1:1: invalid recursive type: Int -> Int +// main/files/recursive8.gno:3:6: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9.gno b/gnovm/tests/files/recursive9.gno index 8181be55d33..3b930ee248d 100644 --- a/gnovm/tests/files/recursive9.gno +++ b/gnovm/tests/files/recursive9.gno @@ -5,4 +5,4 @@ type Int = Int func main() {} // Error: -// main/files/recursive9.gno:1:1: invalid recursive type: Int -> Int +// main/files/recursive9.gno:3:6: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9a.gno b/gnovm/tests/files/recursive9a.gno index b96efa090e4..acd11893bad 100644 --- a/gnovm/tests/files/recursive9a.gno +++ b/gnovm/tests/files/recursive9a.gno @@ -5,4 +5,4 @@ type Int = *Int func main() {} // Error: -// main/files/recursive9a.gno:1:1: invalid recursive type: Int -> Int \ No newline at end of file +// main/files/recursive9a.gno:3:6: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9b.gno b/gnovm/tests/files/recursive9b.gno index e033349d597..3901099ec60 100644 --- a/gnovm/tests/files/recursive9b.gno +++ b/gnovm/tests/files/recursive9b.gno @@ -5,4 +5,4 @@ type Int = func() Int func main() {} // Error: -// main/files/recursive9b.gno:1:1: invalid recursive type: Int -> Int \ No newline at end of file +// main/files/recursive9b.gno:3:6: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9c.gno b/gnovm/tests/files/recursive9c.gno index ad865978920..bf08d406dc2 100644 --- a/gnovm/tests/files/recursive9c.gno +++ b/gnovm/tests/files/recursive9c.gno @@ -5,4 +5,4 @@ type Int = []Int func main() {} // Error: -// main/files/recursive9c.gno:1:1: invalid recursive type: Int -> Int +// main/files/recursive9c.gno:3:6: invalid recursive type: Int -> Int diff --git a/gnovm/tests/files/recursive9d.gno b/gnovm/tests/files/recursive9d.gno index ae7310ede0f..7ea4c934c65 100644 --- a/gnovm/tests/files/recursive9d.gno +++ b/gnovm/tests/files/recursive9d.gno @@ -7,4 +7,4 @@ type S = struct { func main() {} // Error: -// main/files/recursive9d.gno:1:1: invalid recursive type: S -> S +// main/files/recursive9d.gno:3:6: invalid recursive type: S -> S diff --git a/gnovm/tests/files/switch13.gno b/gnovm/tests/files/switch13.gno index b2223c85256..f69f09d1037 100644 --- a/gnovm/tests/files/switch13.gno +++ b/gnovm/tests/files/switch13.gno @@ -14,4 +14,4 @@ func main() { } // Error: -// main/files/switch13.gno:0:0: i is not a type +// main/files/switch13.gno:8:0: i is not a type diff --git a/gnovm/tests/files/types/assign_literal11.gno b/gnovm/tests/files/types/assign_literal11.gno index 851fe74593d..ab916e4c752 100644 --- a/gnovm/tests/files/types/assign_literal11.gno +++ b/gnovm/tests/files/types/assign_literal11.gno @@ -8,4 +8,4 @@ func main() { } // Error: -// main/files/types/assign_literal11.gno:6:2: cannot assign to (const (3.14 bigdec)) +// main/files/types/assign_literal11.gno:6:2: cannot assign to const Pi diff --git a/gnovm/tests/files/types/assign_literal3.gno b/gnovm/tests/files/types/assign_literal3.gno index e4a4441853d..ce051b0dcbb 100644 --- a/gnovm/tests/files/types/assign_literal3.gno +++ b/gnovm/tests/files/types/assign_literal3.gno @@ -5,4 +5,4 @@ func main() { } // Error: -// main/files/types/assign_literal3.gno:4:2: cannot assign to (const (true bool)) +// main/files/types/assign_literal3.gno:4:2: cannot assign to uverse true diff --git a/gnovm/tests/files/types/assign_nil.gno b/gnovm/tests/files/types/assign_nil.gno index 8c756da3b60..ecbca26dad0 100644 --- a/gnovm/tests/files/types/assign_nil.gno +++ b/gnovm/tests/files/types/assign_nil.gno @@ -8,4 +8,4 @@ func main() { } // Error: -// main/files/types/assign_nil.gno:7:2: cannot assign to (const (undefined)) +// main/files/types/assign_nil.gno:7:2: cannot assign to uverse nil diff --git a/gnovm/tests/files/types/assign_nil2.gno b/gnovm/tests/files/types/assign_nil2.gno index fd7d509fccc..a1559d9de1f 100644 --- a/gnovm/tests/files/types/assign_nil2.gno +++ b/gnovm/tests/files/types/assign_nil2.gno @@ -8,4 +8,4 @@ func main() { } // Error: -// main/files/types/assign_nil2.gno:7:2: cannot assign to (const (undefined)) +// main/files/types/assign_nil2.gno:7:2: cannot assign to uverse nil diff --git a/gnovm/tests/files/var18.gno b/gnovm/tests/files/var18.gno index f01d3871d39..475c45f6e38 100644 --- a/gnovm/tests/files/var18.gno +++ b/gnovm/tests/files/var18.gno @@ -5,4 +5,4 @@ func main() { } // Error: -// main/files/var18.gno:4:6: missing init expr for c +// main/files/var18.gno:4:6: missing init expr for c diff --git a/gnovm/tests/files/var19.gno b/gnovm/tests/files/var19.gno index 99d7452f603..2856d6cd05a 100644 --- a/gnovm/tests/files/var19.gno +++ b/gnovm/tests/files/var19.gno @@ -1,12 +1,11 @@ package main func main() { - var a, b, c = 1, a+1 - + var a, b, c = 1, a + 1 println(a) println(b) println(c) } // Error: -// main/files/var19.gno:4:6: missing init expr for c +// main/files/var19.gno:4:6: missing init expr for c diff --git a/gnovm/tests/files/var22.gno b/gnovm/tests/files/var22.gno index 3f85f0f156d..5b21f7aa5bc 100644 --- a/gnovm/tests/files/var22.gno +++ b/gnovm/tests/files/var22.gno @@ -11,4 +11,4 @@ func main() { } // Error: -// main/files/var22.gno:8:6: missing init expr for c +// main/files/var22.gno:8:6: missing init expr for c From 43dd3f33e82c28169f1eedce38a6108167c4e5c3 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:28:50 -0400 Subject: [PATCH 35/64] feat(tm2): add sdk/params module (#2920) - [x] port x/params -> sdk/params b930513083e8485981878f9763bd3b49a25c3785 - [x] inject in vmkeeper + add std.SetConfig 602245d2efde7af76fd9846c57a91838b2024f2d - [x] implement in `gnoland` 783a044e7505e7fde074bb7a1560b69107132228 - [x] appchain - [x] rpc query - [x] txtar - [x] implement or add comment where we should use it in the existing codebase - [x] namespace's realm target - [ ] questions - [x] do we want a `std.GetConfig` from the contract part? -> No, it allows unsafe, complex, and implicit patterns. If you want to get a value from another contract, you can either import it or use a registry pattern. This approach preserves type safety and other GNOVM protections. - [ ] do we want to restrict the realms able to call `SetConfig` (only `r/sys`), or maybe set an expensive gas price? - [x] after discussion with jae - [x] Rename Config -> Param for consistency - [x] Remove `interface{}` from the setters and use specific types, including in the tm2 implementation (string, uint64, int64, bool, bytes) - [x] Remove the `.` suffix addition, but ensure that the type is explicitly defined by the user; and remove the table. - [x] Remove the types table from the tm2 implementation Related #1418 Related #1856 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- gno.land/cmd/gnoland/testdata/params.txtar | 65 +++++++++ gno.land/pkg/gnoland/app.go | 16 ++- gno.land/pkg/sdk/vm/builtins.go | 23 +++ gno.land/pkg/sdk/vm/common_test.go | 4 +- gno.land/pkg/sdk/vm/gas_test.go | 2 +- gno.land/pkg/sdk/vm/keeper.go | 19 ++- gno.land/pkg/sdk/vm/keeper_test.go | 56 +++++++- gnovm/stdlibs/generated.go | 130 +++++++++++++++++ gnovm/stdlibs/std/context.go | 1 + gnovm/stdlibs/std/params.gno | 13 ++ gnovm/stdlibs/std/params.go | 72 ++++++++++ misc/genstd/Makefile | 6 + tm2/pkg/sdk/auth/keeper.go | 12 +- tm2/pkg/sdk/bank/keeper.go | 4 +- tm2/pkg/sdk/params/doc.go | 15 ++ tm2/pkg/sdk/params/handler.go | 79 +++++++++++ tm2/pkg/sdk/params/handler_test.go | 58 ++++++++ tm2/pkg/sdk/params/keeper.go | 157 +++++++++++++++++++++ tm2/pkg/sdk/params/keeper_test.go | 142 +++++++++++++++++++ tm2/pkg/sdk/params/test_common.go | 46 ++++++ tm2/pkg/store/README.md | 12 -- 21 files changed, 901 insertions(+), 31 deletions(-) create mode 100644 gno.land/cmd/gnoland/testdata/params.txtar create mode 100644 gnovm/stdlibs/std/params.gno create mode 100644 gnovm/stdlibs/std/params.go create mode 100644 misc/genstd/Makefile create mode 100644 tm2/pkg/sdk/params/doc.go create mode 100644 tm2/pkg/sdk/params/handler.go create mode 100644 tm2/pkg/sdk/params/handler_test.go create mode 100644 tm2/pkg/sdk/params/keeper.go create mode 100644 tm2/pkg/sdk/params/keeper_test.go create mode 100644 tm2/pkg/sdk/params/test_common.go diff --git a/gno.land/cmd/gnoland/testdata/params.txtar b/gno.land/cmd/gnoland/testdata/params.txtar new file mode 100644 index 00000000000..30363aa6369 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/params.txtar @@ -0,0 +1,65 @@ +# test for https://github.com/gnolang/gno/pull/2920 + +gnoland start + +# query before adding the package +gnokey query params/vm/gno.land/r/sys/setter.foo.string +stdout 'data: $' +gnokey query params/vm/gno.land/r/sys/setter.bar.bool +stdout 'data: $' +gnokey query params/vm/gno.land/r/sys/setter.baz.int64 +stdout 'data: $' + +gnokey maketx addpkg -pkgdir $WORK/setter -pkgpath gno.land/r/sys/setter -gas-fee 1000000ugnot -gas-wanted 100000000 -broadcast -chainid=tendermint_test test1 + +# query after adding the package, but before setting values +gnokey query params/vm/gno.land/r/sys/setter.foo.string +stdout 'data: $' +gnokey query params/vm/gno.land/r/sys/setter.bar.bool +stdout 'data: $' +gnokey query params/vm/gno.land/r/sys/setter.baz.int64 +stdout 'data: $' + + +# set foo (string) +gnokey maketx call -pkgpath gno.land/r/sys/setter -func SetFoo -args foo1 -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 +gnokey query params/vm/gno.land/r/sys/setter.foo.string +stdout 'data: "foo1"' + +# override foo +gnokey maketx call -pkgpath gno.land/r/sys/setter -func SetFoo -args foo2 -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 +gnokey query params/vm/gno.land/r/sys/setter.foo.string +stdout 'data: "foo2"' + + +# set bar (bool) +gnokey maketx call -pkgpath gno.land/r/sys/setter -func SetBar -args true -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 +gnokey query params/vm/gno.land/r/sys/setter.bar.bool +stdout 'data: true' + +# override bar +gnokey maketx call -pkgpath gno.land/r/sys/setter -func SetBar -args false -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 +gnokey query params/vm/gno.land/r/sys/setter.bar.bool +stdout 'data: false' + + +# set baz (bool) +gnokey maketx call -pkgpath gno.land/r/sys/setter -func SetBaz -args 1337 -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 +gnokey query params/vm/gno.land/r/sys/setter.baz.int64 +stdout 'data: "1337"' + +# override baz +gnokey maketx call -pkgpath gno.land/r/sys/setter -func SetBaz -args 31337 -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1 +gnokey query params/vm/gno.land/r/sys/setter.baz.int64 +stdout 'data: "31337"' + +-- setter/setter.gno -- +package setter + +import ( + "std" +) + +func SetFoo(newFoo string) { std.SetParamString("foo.string", newFoo) } +func SetBar(newBar bool) { std.SetParamBool("bar.bool", newBar) } +func SetBaz(newBaz int64) { std.SetParamInt64("baz.int64", newBaz) } diff --git a/gno.land/pkg/gnoland/app.go b/gno.land/pkg/gnoland/app.go index ca746dbe386..e784f2148aa 100644 --- a/gno.land/pkg/gnoland/app.go +++ b/gno.land/pkg/gnoland/app.go @@ -19,6 +19,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/sdk" "github.com/gnolang/gno/tm2/pkg/sdk/auth" "github.com/gnolang/gno/tm2/pkg/sdk/bank" + "github.com/gnolang/gno/tm2/pkg/sdk/params" "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store" "github.com/gnolang/gno/tm2/pkg/store/dbadapter" @@ -87,12 +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) + paramsKpr := params.NewParamsKeeper(mainKey, "vm") + vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, paramsKpr) // Set InitChainer icc := cfg.InitChainerConfig icc.baseApp = baseApp - icc.acctKpr, icc.bankKpr, icc.vmKpr = acctKpr, bankKpr, vmk + icc.acctKpr, icc.bankKpr, icc.vmKpr, icc.paramsKpr = acctKpr, bankKpr, vmk, paramsKpr baseApp.SetInitChainer(icc.InitChainer) // Set AnteHandler @@ -147,6 +149,7 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) { // Set a handler Route. baseApp.Router().AddRoute("auth", auth.NewHandler(acctKpr)) baseApp.Router().AddRoute("bank", bank.NewHandler(bankKpr)) + baseApp.Router().AddRoute("params", params.NewHandler(paramsKpr)) baseApp.Router().AddRoute("vm", vm.NewHandler(vmk)) // Load latest version. @@ -224,10 +227,11 @@ type InitChainerConfig struct { // 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 + baseApp *sdk.BaseApp + vmKpr vm.VMKeeperI + acctKpr auth.AccountKeeperI + bankKpr bank.BankKeeperI + paramsKpr params.ParamsKeeperI } // InitChainer is the function that can be used as a [sdk.InitChainer]. diff --git a/gno.land/pkg/sdk/vm/builtins.go b/gno.land/pkg/sdk/vm/builtins.go index d4d6b6032b2..161e459873d 100644 --- a/gno.land/pkg/sdk/vm/builtins.go +++ b/gno.land/pkg/sdk/vm/builtins.go @@ -55,3 +55,26 @@ func (bnk *SDKBanker) RemoveCoin(b32addr crypto.Bech32Address, denom string, amo panic(err) } } + +// ---------------------------------------- +// SDKParams + +type SDKParams struct { + vmk *VMKeeper + ctx sdk.Context +} + +func NewSDKParams(vmk *VMKeeper, ctx sdk.Context) *SDKParams { + return &SDKParams{ + vmk: vmk, + ctx: ctx, + } +} + +func (prm *SDKParams) SetString(key, value string) { prm.vmk.prmk.SetString(prm.ctx, key, value) } +func (prm *SDKParams) SetBool(key string, value bool) { prm.vmk.prmk.SetBool(prm.ctx, key, value) } +func (prm *SDKParams) SetInt64(key string, value int64) { prm.vmk.prmk.SetInt64(prm.ctx, key, value) } +func (prm *SDKParams) SetUint64(key string, value uint64) { + prm.vmk.prmk.SetUint64(prm.ctx, key, value) +} +func (prm *SDKParams) SetBytes(key string, value []byte) { prm.vmk.prmk.SetBytes(prm.ctx, key, value) } diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index 66975fba923..7380d3e0f72 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -11,6 +11,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/sdk" authm "github.com/gnolang/gno/tm2/pkg/sdk/auth" bankm "github.com/gnolang/gno/tm2/pkg/sdk/bank" + paramsm "github.com/gnolang/gno/tm2/pkg/sdk/params" "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store" "github.com/gnolang/gno/tm2/pkg/store/dbadapter" @@ -47,7 +48,8 @@ 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) + prmk := paramsm.NewParamsKeeper(iavlCapKey, "params") + vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, prmk) mcw := ms.MultiCacheWrap() vmk.Initialize(log.NewNoopLogger(), mcw) diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index 4171b1cdbc3..53809a7f223 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -74,7 +74,7 @@ func TestAddPkgDeliverTx(t *testing.T) { assert.True(t, res.IsOK()) // NOTE: let's try to keep this bellow 100_000 :) - assert.Equal(t, int64(92825), gasDeliver) + assert.Equal(t, int64(93825), gasDeliver) } // Enough gas for a failed transaction. diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index f069cce3723..ef1705c7ae9 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -23,6 +23,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/sdk" "github.com/gnolang/gno/tm2/pkg/sdk/auth" "github.com/gnolang/gno/tm2/pkg/sdk/bank" + "github.com/gnolang/gno/tm2/pkg/sdk/params" "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store" "github.com/gnolang/gno/tm2/pkg/store/dbadapter" @@ -59,6 +60,7 @@ type VMKeeper struct { iavlKey store.StoreKey acck auth.AccountKeeper bank bank.BankKeeper + prmk params.ParamsKeeper // cached, the DeliverTx persistent state. gnoStore gno.Store @@ -70,13 +72,14 @@ func NewVMKeeper( iavlKey store.StoreKey, acck auth.AccountKeeper, bank bank.BankKeeper, + prmk params.ParamsKeeper, ) *VMKeeper { - // TODO: create an Options struct to avoid too many constructor parameters vmk := &VMKeeper{ baseKey: baseKey, iavlKey: iavlKey, acck: acck, bank: bank, + prmk: prmk, } return vmk } @@ -222,9 +225,15 @@ func (vm *VMKeeper) getGnoTransactionStore(ctx sdk.Context) gno.TransactionStore // Namespace can be either a user or crypto address. var reNamespace = regexp.MustCompile(`^gno.land/(?:r|p)/([\.~_a-zA-Z0-9]+)`) +const ( + sysUsersPkgParamKey = "vm/gno.land/r/sys/params.string" + sysUsersPkgDefault = "gno.land/r/sys/users" +) + // checkNamespacePermission check if the user as given has correct permssion to on the given pkg path func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Address, pkgPath string) error { - const sysUsersPkg = "gno.land/r/sys/users" + sysUsersPkg := sysUsersPkgDefault + vm.prmk.GetString(ctx, sysUsersPkgParamKey, &sysUsersPkg) store := vm.getGnoTransactionStore(ctx) @@ -258,6 +267,7 @@ func (vm *VMKeeper) checkNamespacePermission(ctx sdk.Context, creator crypto.Add OrigPkgAddr: pkgAddr.Bech32(), // XXX: should we remove the banker ? Banker: NewSDKBanker(vm, ctx), + Params: NewSDKParams(vm, ctx), EventLogger: ctx.EventLogger(), } @@ -358,6 +368,7 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { OrigSendSpent: new(std.Coins), OrigPkgAddr: pkgAddr.Bech32(), Banker: NewSDKBanker(vm, ctx), + Params: NewSDKParams(vm, ctx), EventLogger: ctx.EventLogger(), } // Parse and run the files, construct *PV. @@ -458,6 +469,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { OrigSendSpent: new(std.Coins), OrigPkgAddr: pkgAddr.Bech32(), Banker: NewSDKBanker(vm, ctx), + Params: NewSDKParams(vm, ctx), EventLogger: ctx.EventLogger(), } // Construct machine and evaluate. @@ -556,6 +568,7 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { OrigSendSpent: new(std.Coins), OrigPkgAddr: pkgAddr.Bech32(), Banker: NewSDKBanker(vm, ctx), + Params: NewSDKParams(vm, ctx), EventLogger: ctx.EventLogger(), } // Parse and run the files, construct *PV. @@ -715,6 +728,7 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res // OrigSendSpent: nil, OrigPkgAddr: pkgAddr.Bech32(), Banker: NewSDKBanker(vm, ctx), // safe as long as ctx is a fork to be discarded. + Params: NewSDKParams(vm, ctx), EventLogger: ctx.EventLogger(), } m := gno.NewMachineWithOptions( @@ -781,6 +795,7 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string // OrigSendSpent: nil, OrigPkgAddr: pkgAddr.Bech32(), Banker: NewSDKBanker(vm, ctx), // safe as long as ctx is a fork to be discarded. + Params: NewSDKParams(vm, ctx), EventLogger: ctx.EventLogger(), } m := gno.NewMachineWithOptions( diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index f6c6b87419d..c6d8e3f5fa0 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -298,6 +298,60 @@ func Echo(msg string) string { assert.Error(t, err) } +// Using x/params from a realm. +func TestVMKeeperParams(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)) + // env.prmk. + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) + + // Create test package. + files := []*std.MemFile{ + {"init.gno", ` +package test + +import "std" + +func init() { + std.SetParamString("foo.string", "foo1") +} + +func Do() string { + std.SetParamInt64("bar.int64", int64(1337)) + std.SetParamString("foo.string", "foo2") // override init + + return "XXX" // return std.GetConfig("gno.land/r/test.foo"), if we want to expose std.GetConfig, maybe as a std.TestGetConfig +}`}, + } + pkgPath := "gno.land/r/test" + msg1 := NewMsgAddPackage(addr, pkgPath, files) + err := env.vmk.AddPackage(ctx, msg1) + assert.NoError(t, err) + + // Run Echo function. + coins := std.MustParseCoins(ugnot.ValueString(9_000_000)) + msg2 := NewMsgCall(addr, coins, pkgPath, "Do", []string{}) + + res, err := env.vmk.Call(ctx, msg2) + assert.NoError(t, err) + _ = res + expected := fmt.Sprintf("(\"%s\" string)\n\n", "XXX") // XXX: return something more useful + assert.Equal(t, expected, res) + + var foo string + var bar int64 + env.vmk.prmk.GetString(ctx, "gno.land/r/test.foo.string", &foo) + env.vmk.prmk.GetInt64(ctx, "gno.land/r/test.bar.int64", &bar) + assert.Equal(t, "foo2", foo) + assert.Equal(t, int64(1337), bar) +} + // Assign admin as OrigCaller on deploying the package. func TestVMKeeperOrigCallerInit(t *testing.T) { env := setupTestEnv() @@ -320,7 +374,7 @@ import "std" var admin std.Address func init() { - admin = std.GetOrigCaller() + admin = std.GetOrigCaller() } func Echo(msg string) string { diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 7693e9d6e70..b0788fc6d1b 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -720,6 +720,136 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "std", + "setParamString", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + {Name: gno.N("p1"), Type: gno.X("string")}, + }, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 string + rp1 = reflect.ValueOf(&p1).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) + + libs_std.X_setParamString( + m, + p0, p1) + }, + }, + { + "std", + "setParamBool", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + {Name: gno.N("p1"), Type: gno.X("bool")}, + }, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 bool + rp1 = reflect.ValueOf(&p1).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) + + libs_std.X_setParamBool( + m, + p0, p1) + }, + }, + { + "std", + "setParamInt64", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + {Name: gno.N("p1"), Type: gno.X("int64")}, + }, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 int64 + rp1 = reflect.ValueOf(&p1).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) + + libs_std.X_setParamInt64( + m, + p0, p1) + }, + }, + { + "std", + "setParamUint64", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + {Name: gno.N("p1"), Type: gno.X("uint64")}, + }, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 uint64 + rp1 = reflect.ValueOf(&p1).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) + + libs_std.X_setParamUint64( + m, + p0, p1) + }, + }, + { + "std", + "setParamBytes", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + {Name: gno.N("p1"), Type: gno.X("[]byte")}, + }, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + p1 []byte + rp1 = reflect.ValueOf(&p1).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) + + libs_std.X_setParamBytes( + m, + p0, p1) + }, + }, { "testing", "unixNano", diff --git a/gnovm/stdlibs/std/context.go b/gnovm/stdlibs/std/context.go index ff5c91a14eb..a0dafe5dc44 100644 --- a/gnovm/stdlibs/std/context.go +++ b/gnovm/stdlibs/std/context.go @@ -18,6 +18,7 @@ type ExecContext struct { OrigSend std.Coins OrigSendSpent *std.Coins // mutable Banker BankerInterface + Params ParamsInterface EventLogger *sdk.EventLogger } diff --git a/gnovm/stdlibs/std/params.gno b/gnovm/stdlibs/std/params.gno new file mode 100644 index 00000000000..ce400270cda --- /dev/null +++ b/gnovm/stdlibs/std/params.gno @@ -0,0 +1,13 @@ +package std + +func setParamString(key string, val string) +func setParamBool(key string, val bool) +func setParamInt64(key string, val int64) +func setParamUint64(key string, val uint64) +func setParamBytes(key string, val []byte) + +func SetParamString(key string, val string) { setParamString(key, val) } +func SetParamBool(key string, val bool) { setParamBool(key, val) } +func SetParamInt64(key string, val int64) { setParamInt64(key, val) } +func SetParamUint64(key string, val uint64) { setParamUint64(key, val) } +func SetParamBytes(key string, val []byte) { setParamBytes(key, val) } diff --git a/gnovm/stdlibs/std/params.go b/gnovm/stdlibs/std/params.go new file mode 100644 index 00000000000..e21bd9912dd --- /dev/null +++ b/gnovm/stdlibs/std/params.go @@ -0,0 +1,72 @@ +package std + +import ( + "fmt" + "strings" + "unicode" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" +) + +// ParamsInterface is the interface through which Gno is capable of accessing +// the blockchain's params. +// +// The name is what it is to avoid a collision with Gno's Params, when +// transpiling. +type ParamsInterface interface { + SetString(key, val string) + SetBool(key string, val bool) + SetInt64(key string, val int64) + SetUint64(key string, val uint64) + SetBytes(key string, val []byte) +} + +func X_setParamString(m *gno.Machine, key, val string) { + pk := pkey(m, key, "string") + GetContext(m).Params.SetString(pk, val) +} + +func X_setParamBool(m *gno.Machine, key string, val bool) { + pk := pkey(m, key, "bool") + GetContext(m).Params.SetBool(pk, val) +} + +func X_setParamInt64(m *gno.Machine, key string, val int64) { + pk := pkey(m, key, "int64") + GetContext(m).Params.SetInt64(pk, val) +} + +func X_setParamUint64(m *gno.Machine, key string, val uint64) { + pk := pkey(m, key, "uint64") + GetContext(m).Params.SetUint64(pk, val) +} + +func X_setParamBytes(m *gno.Machine, key string, val []byte) { + pk := pkey(m, key, "bytes") + GetContext(m).Params.SetBytes(pk, val) +} + +func pkey(m *gno.Machine, key string, kind string) string { + // validate key. + untypedKey := strings.TrimSuffix(key, "."+kind) + if key == untypedKey { + m.Panic(typedString("invalid param key: " + key)) + } + + if len(key) == 0 { + m.Panic(typedString("empty param key")) + } + first := rune(key[0]) + if !unicode.IsLetter(first) && first != '_' { + m.Panic(typedString("invalid param key: " + key)) + } + for _, char := range untypedKey[1:] { + if !unicode.IsLetter(char) && !unicode.IsDigit(char) && char != '_' { + m.Panic(typedString("invalid param key: " + key)) + } + } + + // decorate key with realm and type. + _, rlmPath := currentRealm(m) + return fmt.Sprintf("%s.%s", rlmPath, key) +} diff --git a/misc/genstd/Makefile b/misc/genstd/Makefile new file mode 100644 index 00000000000..2022a6cc2b4 --- /dev/null +++ b/misc/genstd/Makefile @@ -0,0 +1,6 @@ +run: + cd ../../gnovm/stdlibs && go run ../../misc/genstd + cd ../../gnovm/tests/stdlibs && go run ../../../misc/genstd + +test: + go test -v . diff --git a/tm2/pkg/sdk/auth/keeper.go b/tm2/pkg/sdk/auth/keeper.go index e43b5389844..7669b8ace73 100644 --- a/tm2/pkg/sdk/auth/keeper.go +++ b/tm2/pkg/sdk/auth/keeper.go @@ -31,11 +31,6 @@ func NewAccountKeeper( } } -// Logger returns a module-specific logger. -func (ak AccountKeeper) Logger(ctx sdk.Context) *slog.Logger { - return ctx.Logger().With("module", fmt.Sprintf("auth")) -} - // NewAccountWithAddress implements AccountKeeper. func (ak AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr crypto.Address) std.Account { acc := ak.proto() @@ -53,7 +48,12 @@ func (ak AccountKeeper) NewAccountWithAddress(ctx sdk.Context, addr crypto.Addre return acc } -// GetAccount implements AccountKeeper. +// Logger returns a module-specific logger. +func (ak AccountKeeper) Logger(ctx sdk.Context) *slog.Logger { + return ctx.Logger().With("module", ModuleName) +} + +// GetAccount returns a specific account in the AccountKeeper. func (ak AccountKeeper) GetAccount(ctx sdk.Context, addr crypto.Address) std.Account { stor := ctx.Store(ak.key) bz := stor.Get(AddressStoreKey(addr)) diff --git a/tm2/pkg/sdk/bank/keeper.go b/tm2/pkg/sdk/bank/keeper.go index 5d3699c99ef..f98e6b3e225 100644 --- a/tm2/pkg/sdk/bank/keeper.go +++ b/tm2/pkg/sdk/bank/keeper.go @@ -25,8 +25,8 @@ type BankKeeperI interface { var _ BankKeeperI = BankKeeper{} -// BBankKeeper only allows transfers between accounts without the possibility of -// creating coins. It implements the BankKeeper interface. +// BankKeeper only allows transfers between accounts without the possibility of +// creating coins. It implements the BankKeeperI interface. type BankKeeper struct { ViewKeeper diff --git a/tm2/pkg/sdk/params/doc.go b/tm2/pkg/sdk/params/doc.go new file mode 100644 index 00000000000..a433b5eb115 --- /dev/null +++ b/tm2/pkg/sdk/params/doc.go @@ -0,0 +1,15 @@ +// Package params provides a lightweight implementation inspired by the x/params +// module of the Cosmos SDK. +// +// It includes a keeper for managing key-value pairs with module identifiers as +// prefixes, along with a global querier for retrieving any key from any module. +// +// Changes: This version removes the concepts of subspaces and proposals, +// allowing the creation of multiple keepers identified by a provided prefix. +// Proposals may be added later when governance modules are introduced. The +// transient store and .Modified helper have also been removed but can be +// implemented later if needed. Keys are represented as strings instead of +// []byte. +// +// XXX: removes isAlphaNum validation for keys. +package params diff --git a/tm2/pkg/sdk/params/handler.go b/tm2/pkg/sdk/params/handler.go new file mode 100644 index 00000000000..b662fc06c58 --- /dev/null +++ b/tm2/pkg/sdk/params/handler.go @@ -0,0 +1,79 @@ +package params + +import ( + "fmt" + "strings" + + abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/std" +) + +type paramsHandler struct { + params ParamsKeeper +} + +func NewHandler(params ParamsKeeper) paramsHandler { + return paramsHandler{ + params: params, + } +} + +func (bh paramsHandler) Process(ctx sdk.Context, msg std.Msg) sdk.Result { + errMsg := fmt.Sprintf("unrecognized params message type: %T", msg) + return abciResult(std.ErrUnknownRequest(errMsg)) +} + +//---------------------------------------- +// Query + +func (bh paramsHandler) Query(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) { + switch secondPart(req.Path) { + case bh.params.prefix: + return bh.queryParam(ctx, req) + default: + res = sdk.ABCIResponseQueryFromError( + std.ErrUnknownRequest("unknown params query endpoint")) + return + } +} + +// queryParam returns param for a key. +func (bh paramsHandler) queryParam(ctx sdk.Context, req abci.RequestQuery) (res abci.ResponseQuery) { + // parse key from path. + key := thirdPartWithSlashes(req.Path) + if key == "" { + res = sdk.ABCIResponseQueryFromError( + std.ErrUnknownRequest("param key is empty")) + } + + // XXX: validate? + + val := bh.params.GetRaw(ctx, key) + + res.Data = val + return +} + +//---------------------------------------- +// misc + +func abciResult(err error) sdk.Result { + return sdk.ABCIResultFromError(err) +} + +// returns the second component of a path. +func secondPart(path string) string { + parts := strings.SplitN(path, "/", 3) + if len(parts) < 2 { + return "" + } else { + return parts[1] + } +} + +// returns the third component of a path, including other slashes. +func thirdPartWithSlashes(path string) string { + split := strings.SplitN(path, "/", 3) + return split[2] +} diff --git a/tm2/pkg/sdk/params/handler_test.go b/tm2/pkg/sdk/params/handler_test.go new file mode 100644 index 00000000000..1fff5d007d3 --- /dev/null +++ b/tm2/pkg/sdk/params/handler_test.go @@ -0,0 +1,58 @@ +package params + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" + + 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/sdk" + tu "github.com/gnolang/gno/tm2/pkg/sdk/testutils" +) + +func TestInvalidMsg(t *testing.T) { + t.Parallel() + + h := NewHandler(ParamsKeeper{}) + res := h.Process(sdk.NewContext(sdk.RunTxModeDeliver, nil, &bft.Header{ChainID: "test-chain"}, nil), tu.NewTestMsg()) + require.False(t, res.IsOK()) + require.True(t, strings.Contains(res.Log, "unrecognized params message type")) +} + +func TestQuery(t *testing.T) { + t.Parallel() + + env := setupTestEnv() + h := NewHandler(env.keeper) + + req := abci.RequestQuery{ + Path: "params/params_test/foo/bar.string", + } + + res := h.Query(env.ctx, req) + require.Nil(t, res.Error) + require.NotNil(t, res) + require.Nil(t, res.Data) + + env.keeper.SetString(env.ctx, "foo/bar.string", "baz") + + res = h.Query(env.ctx, req) + require.Nil(t, res.Error) + require.NotNil(t, res) + require.Equal(t, string(res.Data), `"baz"`) +} + +func TestQuerierRouteNotFound(t *testing.T) { + t.Parallel() + + env := setupTestEnv() + h := NewHandler(env.keeper) + req := abci.RequestQuery{ + Path: "params/notfound", + Data: []byte{}, + } + res := h.Query(env.ctx, req) + require.Error(t, res.Error) +} diff --git a/tm2/pkg/sdk/params/keeper.go b/tm2/pkg/sdk/params/keeper.go new file mode 100644 index 00000000000..ffeb1775acb --- /dev/null +++ b/tm2/pkg/sdk/params/keeper.go @@ -0,0 +1,157 @@ +package params + +import ( + "log/slog" + "strings" + + "github.com/gnolang/gno/tm2/pkg/amino" + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/store" +) + +const ( + ModuleName = "params" + StoreKey = ModuleName +) + +type ParamsKeeperI interface { + GetString(ctx sdk.Context, key string, ptr *string) + GetInt64(ctx sdk.Context, key string, ptr *int64) + GetUint64(ctx sdk.Context, key string, ptr *uint64) + GetBool(ctx sdk.Context, key string, ptr *bool) + GetBytes(ctx sdk.Context, key string, ptr *[]byte) + + SetString(ctx sdk.Context, key string, value string) + SetInt64(ctx sdk.Context, key string, value int64) + SetUint64(ctx sdk.Context, key string, value uint64) + SetBool(ctx sdk.Context, key string, value bool) + SetBytes(ctx sdk.Context, key string, value []byte) + + Has(ctx sdk.Context, key string) bool + GetRaw(ctx sdk.Context, key string) []byte + + // XXX: ListKeys? +} + +var _ ParamsKeeperI = ParamsKeeper{} + +// global paramstore Keeper. +type ParamsKeeper struct { + key store.StoreKey + prefix string +} + +// NewParamsKeeper returns a new ParamsKeeper. +func NewParamsKeeper(key store.StoreKey, prefix string) ParamsKeeper { + return ParamsKeeper{ + key: key, + prefix: prefix, + } +} + +// Logger returns a module-specific logger. +// XXX: why do we expose this? +func (pk ParamsKeeper) Logger(ctx sdk.Context) *slog.Logger { + return ctx.Logger().With("module", ModuleName) +} + +func (pk ParamsKeeper) Has(ctx sdk.Context, key string) bool { + stor := ctx.Store(pk.key) + return stor.Has([]byte(key)) +} + +func (pk ParamsKeeper) GetRaw(ctx sdk.Context, key string) []byte { + stor := ctx.Store(pk.key) + return stor.Get([]byte(key)) +} + +func (pk ParamsKeeper) GetString(ctx sdk.Context, key string, ptr *string) { + checkSuffix(key, ".string") + pk.getIfExists(ctx, key, ptr) +} + +func (pk ParamsKeeper) GetBool(ctx sdk.Context, key string, ptr *bool) { + checkSuffix(key, ".bool") + pk.getIfExists(ctx, key, ptr) +} + +func (pk ParamsKeeper) GetInt64(ctx sdk.Context, key string, ptr *int64) { + checkSuffix(key, ".int64") + pk.getIfExists(ctx, key, ptr) +} + +func (pk ParamsKeeper) GetUint64(ctx sdk.Context, key string, ptr *uint64) { + checkSuffix(key, ".uint64") + pk.getIfExists(ctx, key, ptr) +} + +func (pk ParamsKeeper) GetBytes(ctx sdk.Context, key string, ptr *[]byte) { + checkSuffix(key, ".bytes") + pk.getIfExists(ctx, key, ptr) +} + +func (pk ParamsKeeper) SetString(ctx sdk.Context, key, value string) { + checkSuffix(key, ".string") + pk.set(ctx, key, value) +} + +func (pk ParamsKeeper) SetBool(ctx sdk.Context, key string, value bool) { + checkSuffix(key, ".bool") + pk.set(ctx, key, value) +} + +func (pk ParamsKeeper) SetInt64(ctx sdk.Context, key string, value int64) { + checkSuffix(key, ".int64") + pk.set(ctx, key, value) +} + +func (pk ParamsKeeper) SetUint64(ctx sdk.Context, key string, value uint64) { + checkSuffix(key, ".uint64") + pk.set(ctx, key, value) +} + +func (pk ParamsKeeper) SetBytes(ctx sdk.Context, key string, value []byte) { + checkSuffix(key, ".bytes") + pk.set(ctx, key, value) +} + +func (pk ParamsKeeper) getIfExists(ctx sdk.Context, key string, ptr interface{}) { + stor := ctx.Store(pk.key) + bz := stor.Get([]byte(key)) + if bz == nil { + return + } + err := amino.UnmarshalJSON(bz, ptr) + if err != nil { + panic(err) + } +} + +func (pk ParamsKeeper) get(ctx sdk.Context, key string, ptr interface{}) { + stor := ctx.Store(pk.key) + bz := stor.Get([]byte(key)) + err := amino.UnmarshalJSON(bz, ptr) + if err != nil { + panic(err) + } +} + +func (pk ParamsKeeper) set(ctx sdk.Context, key string, value interface{}) { + stor := ctx.Store(pk.key) + bz, err := amino.MarshalJSON(value) + if err != nil { + panic(err) + } + stor.Set([]byte(key), bz) +} + +func checkSuffix(key, expectedSuffix string) { + var ( + noSuffix = !strings.HasSuffix(key, expectedSuffix) + noName = len(key) == len(expectedSuffix) + // XXX: additional sanity checks? + ) + if noSuffix || noName { + panic(`key should be like "` + expectedSuffix + `"`) + } +} diff --git a/tm2/pkg/sdk/params/keeper_test.go b/tm2/pkg/sdk/params/keeper_test.go new file mode 100644 index 00000000000..45a97ae44ad --- /dev/null +++ b/tm2/pkg/sdk/params/keeper_test.go @@ -0,0 +1,142 @@ +package params + +import ( + "reflect" + "testing" + + "github.com/gnolang/gno/tm2/pkg/amino" + "github.com/stretchr/testify/require" +) + +func TestKeeper(t *testing.T) { + env := setupTestEnv() + ctx, store, keeper := env.ctx, env.store, env.keeper + _ = store // XXX: add store tests? + + require.False(t, keeper.Has(ctx, "param1.string")) + require.False(t, keeper.Has(ctx, "param2.bool")) + require.False(t, keeper.Has(ctx, "param3.uint64")) + require.False(t, keeper.Has(ctx, "param4.int64")) + require.False(t, keeper.Has(ctx, "param5.bytes")) + + // initial set + require.NotPanics(t, func() { keeper.SetString(ctx, "param1.string", "foo") }) + require.NotPanics(t, func() { keeper.SetBool(ctx, "param2.bool", true) }) + require.NotPanics(t, func() { keeper.SetUint64(ctx, "param3.uint64", 42) }) + require.NotPanics(t, func() { keeper.SetInt64(ctx, "param4.int64", -1337) }) + require.NotPanics(t, func() { keeper.SetBytes(ctx, "param5.bytes", []byte("hello world!")) }) + + require.True(t, keeper.Has(ctx, "param1.string")) + require.True(t, keeper.Has(ctx, "param2.bool")) + require.True(t, keeper.Has(ctx, "param3.uint64")) + require.True(t, keeper.Has(ctx, "param4.int64")) + require.True(t, keeper.Has(ctx, "param5.bytes")) + + var ( + param1 string + param2 bool + param3 uint64 + param4 int64 + param5 []byte + ) + + require.NotPanics(t, func() { keeper.GetString(ctx, "param1.string", ¶m1) }) + require.NotPanics(t, func() { keeper.GetBool(ctx, "param2.bool", ¶m2) }) + require.NotPanics(t, func() { keeper.GetUint64(ctx, "param3.uint64", ¶m3) }) + require.NotPanics(t, func() { keeper.GetInt64(ctx, "param4.int64", ¶m4) }) + require.NotPanics(t, func() { keeper.GetBytes(ctx, "param5.bytes", ¶m5) }) + + require.Equal(t, param1, "foo") + require.Equal(t, param2, true) + require.Equal(t, param3, uint64(42)) + require.Equal(t, param4, int64(-1337)) + require.Equal(t, param5, []byte("hello world!")) + + // reset + require.NotPanics(t, func() { keeper.SetString(ctx, "param1.string", "bar") }) + require.NotPanics(t, func() { keeper.SetBool(ctx, "param2.bool", false) }) + require.NotPanics(t, func() { keeper.SetUint64(ctx, "param3.uint64", 12345) }) + require.NotPanics(t, func() { keeper.SetInt64(ctx, "param4.int64", 1000) }) + require.NotPanics(t, func() { keeper.SetBytes(ctx, "param5.bytes", []byte("bye")) }) + + require.True(t, keeper.Has(ctx, "param1.string")) + require.True(t, keeper.Has(ctx, "param2.bool")) + require.True(t, keeper.Has(ctx, "param3.uint64")) + require.True(t, keeper.Has(ctx, "param4.int64")) + require.True(t, keeper.Has(ctx, "param5.bytes")) + + require.NotPanics(t, func() { keeper.GetString(ctx, "param1.string", ¶m1) }) + require.NotPanics(t, func() { keeper.GetBool(ctx, "param2.bool", ¶m2) }) + require.NotPanics(t, func() { keeper.GetUint64(ctx, "param3.uint64", ¶m3) }) + require.NotPanics(t, func() { keeper.GetInt64(ctx, "param4.int64", ¶m4) }) + require.NotPanics(t, func() { keeper.GetBytes(ctx, "param5.bytes", ¶m5) }) + + require.Equal(t, param1, "bar") + require.Equal(t, param2, false) + require.Equal(t, param3, uint64(12345)) + require.Equal(t, param4, int64(1000)) + require.Equal(t, param5, []byte("bye")) + + // invalid sets + require.PanicsWithValue(t, `key should be like ".string"`, func() { keeper.SetString(ctx, "invalid.int64", "hello") }) + require.PanicsWithValue(t, `key should be like ".int64"`, func() { keeper.SetInt64(ctx, "invalid.string", int64(42)) }) + require.PanicsWithValue(t, `key should be like ".uint64"`, func() { keeper.SetUint64(ctx, "invalid.int64", uint64(42)) }) + require.PanicsWithValue(t, `key should be like ".bool"`, func() { keeper.SetBool(ctx, "invalid.int64", true) }) + require.PanicsWithValue(t, `key should be like ".bytes"`, func() { keeper.SetBytes(ctx, "invalid.int64", []byte("hello")) }) +} + +// adapted from TestKeeperSubspace from Cosmos SDK, but adapted to a subspace-less Keeper. +func TestKeeper_internal(t *testing.T) { + env := setupTestEnv() + ctx, store, keeper := env.ctx, env.store, env.keeper + + kvs := []struct { + key string + param interface{} + zero interface{} + ptr interface{} + }{ + {"string", "test", "", new(string)}, + {"bool", true, false, new(bool)}, + {"int16", int16(1), int16(0), new(int16)}, + {"int32", int32(1), int32(0), new(int32)}, + {"int64", int64(1), int64(0), new(int64)}, + {"uint16", uint16(1), uint16(0), new(uint16)}, + {"uint32", uint32(1), uint32(0), new(uint32)}, + {"uint64", uint64(1), uint64(0), new(uint64)}, + {"struct", s{1}, s{0}, new(s)}, + } + + for i, kv := range kvs { + require.NotPanics(t, func() { keeper.set(ctx, kv.key, kv.param) }, "keeper.Set panics, tc #%d", i) + } + + for i, kv := range kvs { + require.NotPanics(t, func() { keeper.getIfExists(ctx, "invalid", kv.ptr) }, "keeper.GetIfExists panics when no value exists, tc #%d", i) + require.Equal(t, kv.zero, indirect(kv.ptr), "keeper.GetIfExists unmarshalls when no value exists, tc #%d", i) + require.Panics(t, func() { keeper.get(ctx, "invalid", kv.ptr) }, "invalid keeper.Get not panics when no value exists, tc #%d", i) + require.Equal(t, kv.zero, indirect(kv.ptr), "invalid keeper.Get unmarshalls when no value exists, tc #%d", i) + + require.NotPanics(t, func() { keeper.getIfExists(ctx, kv.key, kv.ptr) }, "keeper.GetIfExists panics, tc #%d", i) + require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i) + require.NotPanics(t, func() { keeper.get(ctx, kv.key, kv.ptr) }, "keeper.Get panics, tc #%d", i) + require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i) + + require.Panics(t, func() { keeper.get(ctx, "invalid", kv.ptr) }, "invalid keeper.Get not panics when no value exists, tc #%d", i) + require.Equal(t, kv.param, indirect(kv.ptr), "invalid keeper.Get unmarshalls when no value existt, tc #%d", i) + + require.Panics(t, func() { keeper.get(ctx, kv.key, nil) }, "invalid keeper.Get not panics when the pointer is nil, tc #%d", i) + } + + for i, kv := range kvs { + bz := store.Get([]byte(kv.key)) + require.NotNil(t, bz, "store.Get() returns nil, tc #%d", i) + err := amino.UnmarshalJSON(bz, kv.ptr) + require.NoError(t, err, "cdc.UnmarshalJSON() returns error, tc #%d", i) + require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i) + } +} + +type s struct{ I int } + +func indirect(ptr interface{}) interface{} { return reflect.ValueOf(ptr).Elem().Interface() } diff --git a/tm2/pkg/sdk/params/test_common.go b/tm2/pkg/sdk/params/test_common.go new file mode 100644 index 00000000000..8243ee867de --- /dev/null +++ b/tm2/pkg/sdk/params/test_common.go @@ -0,0 +1,46 @@ +package params + +import ( + 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/db/memdb" + "github.com/gnolang/gno/tm2/pkg/log" + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/store" + "github.com/gnolang/gno/tm2/pkg/store/iavl" +) + +type testEnv struct { + ctx sdk.Context + store store.Store + keeper ParamsKeeper +} + +func setupTestEnv() testEnv { + db := memdb.NewMemDB() + paramsCapKey := store.NewStoreKey("paramsCapKey") + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(paramsCapKey, iavl.StoreConstructor, db) + ms.LoadLatestVersion() + + prefix := "params_test" + keeper := NewParamsKeeper(paramsCapKey, prefix) + + ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{Height: 1, ChainID: "test-chain-id"}, log.NewNoopLogger()) + // XXX: context key? + ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ + Block: &abci.BlockParams{ + MaxTxBytes: 1024, + MaxDataBytes: 1024 * 100, + MaxBlockBytes: 1024 * 100, + MaxGas: 10 * 1000 * 1000, + TimeIotaMS: 10, + }, + Validator: &abci.ValidatorParams{ + PubKeyTypeURLs: []string{}, // XXX + }, + }) + + stor := ctx.Store(paramsCapKey) + return testEnv{ctx: ctx, store: stor, keeper: keeper} +} diff --git a/tm2/pkg/store/README.md b/tm2/pkg/store/README.md index abf5c26bc07..24ae0c805ac 100644 --- a/tm2/pkg/store/README.md +++ b/tm2/pkg/store/README.md @@ -116,15 +116,3 @@ type traceOperation struct { ``` `traceOperation.Metadata` is filled with `Store.context` when it is not nil. `TraceContext` is a `map[string]interface{}`. - -## Transient - -`transient.Store` is a base-layer `KVStore` which is automatically discarded at the end of the block. - -```go -type Store struct { - dbadapter.Store -} -``` - -`Store.Store` is a `dbadapter.Store` with a `memdb.NewMemDB()`. All `KVStore` methods are reused. When `Store.Commit()` is called, new `dbadapter.Store` is assigned, discarding previous reference and making it garbage collected. From e34a8f7eb14fb5d255a810ea9ae89d860a790598 Mon Sep 17 00:00:00 2001 From: SunSpirit <48086732+sunspirit99@users.noreply.github.com> Date: Wed, 23 Oct 2024 18:48:35 +0700 Subject: [PATCH 36/64] fix(tm2): enable coin benchmark tests after fixing panic error (#2884) Relate to https://github.com/gnolang/gno/issues/907 Make a few small fixes to get this test working
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
    --- tm2/pkg/std/coin_benchmark_test.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tm2/pkg/std/coin_benchmark_test.go b/tm2/pkg/std/coin_benchmark_test.go index 2d4d2f03890..3cb05612373 100644 --- a/tm2/pkg/std/coin_benchmark_test.go +++ b/tm2/pkg/std/coin_benchmark_test.go @@ -2,12 +2,10 @@ package std import ( "fmt" - "strconv" "testing" ) func BenchmarkCoinsAdditionIntersect(b *testing.B) { - b.Skip("TODO: panicking benchmark") benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) { return func(b *testing.B) { b.Helper() @@ -15,11 +13,16 @@ func BenchmarkCoinsAdditionIntersect(b *testing.B) { coinsA := Coins(make([]Coin, numCoinsA)) coinsB := Coins(make([]Coin, numCoinsB)) + maxCoins := max(numCoinsA, numCoinsB) + denomLength := len(fmt.Sprint(maxCoins)) + for i := 0; i < numCoinsA; i++ { - coinsA[i] = NewCoin("COINZ_"+strconv.Itoa(i), (int64(i))) + denom := fmt.Sprintf("coinz_%0*d", denomLength, i) + coinsA[i] = NewCoin(denom, int64(i+1)) } for i := 0; i < numCoinsB; i++ { - coinsB[i] = NewCoin("COINZ_"+strconv.Itoa(i), (int64(i))) + denom := fmt.Sprintf("coinz_%0*d", denomLength, i) + coinsB[i] = NewCoin(denom, int64(i+1)) } b.ResetTimer() @@ -39,7 +42,6 @@ func BenchmarkCoinsAdditionIntersect(b *testing.B) { } func BenchmarkCoinsAdditionNoIntersect(b *testing.B) { - b.Skip("TODO: panicking benchmark") benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) { return func(b *testing.B) { b.Helper() @@ -47,11 +49,16 @@ func BenchmarkCoinsAdditionNoIntersect(b *testing.B) { coinsA := Coins(make([]Coin, numCoinsA)) coinsB := Coins(make([]Coin, numCoinsB)) + maxCoins := max(numCoinsA, numCoinsB) + denomLength := len(fmt.Sprint(maxCoins)) + for i := 0; i < numCoinsA; i++ { - coinsA[i] = NewCoin("COINZ_"+strconv.Itoa(numCoinsB+i), (int64(i))) + denom := fmt.Sprintf("coinz_%0*d", denomLength, i) + coinsA[i] = NewCoin(denom, int64(i+1)) } for i := 0; i < numCoinsB; i++ { - coinsB[i] = NewCoin("COINZ_"+strconv.Itoa(i), (int64(i))) + denom := fmt.Sprintf("coinz_%0*d", denomLength, i) + coinsB[i] = NewCoin(denom, int64(i+1)) } b.ResetTimer() From 247f2c63b54d75cf9033abb2f1f3c10344f78991 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Wed, 23 Oct 2024 16:29:25 +0200 Subject: [PATCH 37/64] feat(ghverify): emit event when user request verification (#2778) related to #2777
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
    Co-authored-by: 6h057 <15034695+omarsy@users.noreply.github.com> --- examples/gno.land/r/gnoland/ghverify/contract.gno | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/gno.land/r/gnoland/ghverify/contract.gno b/examples/gno.land/r/gnoland/ghverify/contract.gno index 4f2715b79e7..3b8f7fcbbe1 100644 --- a/examples/gno.land/r/gnoland/ghverify/contract.gno +++ b/examples/gno.land/r/gnoland/ghverify/contract.gno @@ -83,6 +83,11 @@ func RequestVerification(githubHandle string) { ); err != nil { panic(err) } + std.Emit( + "verification_requested", + "from", gnoAddress, + "handle", githubHandle, + ) } // GnorkleEntrypoint is the entrypoint to the gnorkle oracle handler. From 5e7183784e385ce3817bf4e19f7a15a8f277e75e Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Thu, 24 Oct 2024 00:41:05 +0900 Subject: [PATCH 38/64] test(p/uint256): Increase Test Coverage for `uint256` Package (#2931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Screenshot 2024-10-10 at 2 53 28 PM Increased the test coverage of the `p/demo/uint256` package. Previously, only about 40% was covered, but now it has increased to 90% (checked in go). The existing implementation of the uint256 function is unmodified except for modifying it to use the strconv package. - [X] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [X] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md). --------- Co-authored-by: Morgan --- .../p/demo/uint256/arithmetic_test.gno | 384 ++++++++++-------- .../gno.land/p/demo/uint256/bitwise_test.gno | 187 ++++++--- examples/gno.land/p/demo/uint256/cmp_test.gno | 200 ++++++--- .../p/demo/uint256/conversion_test.gno | 139 ++++++- examples/gno.land/p/demo/uint256/uint256.gno | 5 +- .../gno.land/p/demo/uint256/uint256_test.gno | 127 ++++++ examples/gno.land/p/demo/uint256/utils.gno | 160 -------- 7 files changed, 760 insertions(+), 442 deletions(-) create mode 100644 examples/gno.land/p/demo/uint256/uint256_test.gno diff --git a/examples/gno.land/p/demo/uint256/arithmetic_test.gno b/examples/gno.land/p/demo/uint256/arithmetic_test.gno index 9f45a507754..079d89fa794 100644 --- a/examples/gno.land/p/demo/uint256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/uint256/arithmetic_test.gno @@ -1,6 +1,8 @@ package uint256 -import "testing" +import ( + "testing" +) type binOp2Test struct { x, y, want string @@ -16,30 +18,45 @@ func TestAdd(t *testing.T) { {"18446744073709551615", "18446744073709551615", "36893488147419103230"}, // uint64 overflow } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + want := MustFromDecimal(tt.want) + got := new(Uint).Add(x, y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Add(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} - got := &Uint{} - got.Add(x, y) +func TestAddOverflow(t *testing.T) { + tests := []struct { + x, y string + want string + overflow bool + }{ + {"0", "1", "1", false}, + {"1", "0", "1", false}, + {"1", "1", "2", false}, + {"10", "10", "20", false}, + {"18446744073709551615", "18446744073709551615", "36893488147419103230", false}, // uint64 overflow, but not Uint256 overflow + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "0", true}, // 2^256 - 1 + 1, should overflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819968", "115792089237316195423570985008687907853269984665640564039457584007913129639935", false}, // (2^255 - 1) + 2^255, no overflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819969", "0", true}, // (2^255 - 1) + (2^255 + 1), should overflow + } - if got.Neq(want) { - t.Errorf("Add(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want, _ := FromDecimal(tt.want) + + got, overflow := new(Uint).AddOverflow(x, y) + + if got.Cmp(want) != 0 || overflow != tt.overflow { + t.Errorf("AddOverflow(%s, %s) = (%s, %v), want (%s, %v)", + tt.x, tt.y, got.ToString(), overflow, tt.want, tt.overflow) } } } @@ -50,33 +67,53 @@ func TestSub(t *testing.T) { {"1", "1", "0"}, {"10", "10", "0"}, {"31337", "1337", "30000"}, - {"2", "3", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // underflow + {"2", "3", twoPow256Sub1}, // underflow } for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + x := MustFromDecimal(tc.x) + y := MustFromDecimal(tc.y) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + want := MustFromDecimal(tc.want) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + got := new(Uint).Sub(x, y) + + if got.Neq(want) { + t.Errorf( + "Sub(%s, %s) = %v, want %v", + tc.x, tc.y, got.ToString(), want.ToString(), + ) } + } +} - got := &Uint{} - got.Sub(x, y) +func TestSubOverflow(t *testing.T) { + tests := []struct { + x, y string + want string + overflow bool + }{ + {"1", "0", "1", false}, + {"1", "1", "0", false}, + {"10", "10", "0", false}, + {"31337", "1337", "30000", false}, + {"0", "1", "115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, // 0 - 1, should underflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "1", "57896044618658097711785492504343953926634992332820282019728792003956564819967", false}, // 2^255 - 1, no underflow + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "57896044618658097711785492504343953926634992332820282019728792003956564819969", "115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, // 2^255 - (2^255 + 1), should underflow + } - if got.Neq(want) { - t.Errorf("Sub(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + for _, tc := range tests { + x := MustFromDecimal(tc.x) + y := MustFromDecimal(tc.y) + want := MustFromDecimal(tc.want) + + got, overflow := new(Uint).SubOverflow(x, y) + + if got.Cmp(want) != 0 || overflow != tc.overflow { + t.Errorf( + "SubOverflow(%s, %s) = (%s, %v), want (%s, %v)", + tc.x, tc.y, got.ToString(), overflow, tc.want, tc.overflow, + ) } } } @@ -89,30 +126,50 @@ func TestMul(t *testing.T) { {"18446744073709551615", "2", "36893488147419103230"}, // uint64 overflow } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) + got := new(Uint).Mul(x, y) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Mul(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } +func TestMulOverflow(t *testing.T) { + tests := []struct { + x string + y string + wantZ string + wantOver bool + }{ + {"0x1", "0x1", "0x1", false}, + {"0x0", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x0", false}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x2", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", true}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x1", true}, + {"0x8000000000000000000000000000000000000000000000000000000000000000", "0x2", "0x0", true}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x2", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", false}, + {"0x100000000000000000", "0x100000000000000000", "0x10000000000000000000000000000000000", false}, + {"0x10000000000000000000000000000000", "0x10000000000000000000000000000000", "0x100000000000000000000000000000000000000000000000000000000000000", false}, + } - got := &Uint{} - got.Mul(x, y) + for _, tt := range tests { + x := MustFromHex(tt.x) + y := MustFromHex(tt.y) + wantZ := MustFromHex(tt.wantZ) - if got.Neq(want) { - t.Errorf("Mul(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + gotZ, gotOver := new(Uint).MulOverflow(x, y) + + if gotZ.Neq(wantZ) { + t.Errorf( + "MulOverflow(%s, %s) = %s, want %s", + tt.x, tt.y, gotZ.ToString(), wantZ.ToString(), + ) + } + if gotOver != tt.wantOver { + t.Errorf("MulOverflow(%s, %s) = %v, want %v", tt.x, tt.y, gotOver, tt.wantOver) } } } @@ -123,32 +180,19 @@ func TestDiv(t *testing.T) { {"31337", "0", "0"}, {"0", "31337", "0"}, {"1", "1", "1"}, + {"1000000000000000000", "3", "333333333333333333"}, + {twoPow256Sub1, "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) - got := &Uint{} - got.Div(x, y) + got := new(Uint).Div(x, y) if got.Neq(want) { - t.Errorf("Div(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Div(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } } } @@ -160,32 +204,56 @@ func TestMod(t *testing.T) { {"0", "31337", "0"}, {"2", "31337", "2"}, {"1", "1", "0"}, + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "1"}, // 2^256 - 1 mod 2 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "3", "0"}, // 2^256 - 1 mod 3 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "57896044618658097711785492504343953926634992332820282019728792003956564819968", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // 2^256 - 1 mod 2^255 } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + got := new(Uint).Mod(x, y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} - got := &Uint{} - got.Mod(x, y) +func TestMulMod(t *testing.T) { + tests := []struct { + x string + y string + m string + want string + }{ + {"0x1", "0x1", "0x2", "0x1"}, + {"0x10", "0x10", "0x7", "0x4"}, + {"0x100", "0x100", "0x17", "0x9"}, + {"0x31337", "0x31337", "0x31338", "0x1"}, + {"0x0", "0x31337", "0x31338", "0x0"}, + {"0x31337", "0x0", "0x31338", "0x0"}, + {"0x2", "0x3", "0x5", "0x1"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x0"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0x1"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffff", "0x0"}, + } + + for _, tt := range tests { + x := MustFromHex(tt.x) + y := MustFromHex(tt.y) + m := MustFromHex(tt.m) + want := MustFromHex(tt.want) + + got := new(Uint).MulMod(x, y, m) if got.Neq(want) { - t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf( + "MulMod(%s, %s, %s) = %s, want %s", + tt.x, tt.y, tt.m, got.ToString(), want.ToString(), + ) } } } @@ -206,30 +274,11 @@ func TestDivMod(t *testing.T) { {"2", "31337", "0", "2"}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - wantDiv, err := FromDecimal(tc.wantDiv) - if err != nil { - t.Error(err) - continue - } - - wantMod, err := FromDecimal(tc.wantMod) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + wantDiv := MustFromDecimal(tt.wantDiv) + wantMod := MustFromDecimal(tt.wantMod) gotDiv := new(Uint) gotMod := new(Uint) @@ -237,13 +286,13 @@ func TestDivMod(t *testing.T) { for i := range gotDiv.arr { if gotDiv.arr[i] != wantDiv.arr[i] { - t.Errorf("DivMod(%s, %s) got Div %v, want Div %v", tc.x, tc.y, gotDiv, wantDiv) + t.Errorf("DivMod(%s, %s) got Div %v, want Div %v", tt.x, tt.y, gotDiv, wantDiv) break } } for i := range gotMod.arr { if gotMod.arr[i] != wantMod.arr[i] { - t.Errorf("DivMod(%s, %s) got Mod %v, want Mod %v", tc.x, tc.y, gotMod, wantMod) + t.Errorf("DivMod(%s, %s) got Mod %v, want Mod %v", tt.x, tt.y, gotMod, wantMod) break } } @@ -259,27 +308,17 @@ func TestNeg(t *testing.T) { {"115792089237316195423570985008687907853269984665640564039457584007913129608599", "31337"}, {"0", "0"}, {"2", "115792089237316195423570985008687907853269984665640564039457584007913129639934"}, - {"1", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, + {"1", twoPow256Sub1}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + want := MustFromDecimal(tt.want) - got := &Uint{} - got.Neg(x) + got := new(Uint).Neg(x) if got.Neq(want) { - t.Errorf("Neg(%s) = %v, want %v", tc.x, got.ToString(), want.ToString()) + t.Errorf("Neg(%s) = %v, want %v", tt.x, got.ToString(), want.ToString()) } } } @@ -297,30 +336,57 @@ func TestExp(t *testing.T) { {"2", "256", "0"}, // overflow } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + got := new(Uint).Exp(x, y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf( + "Exp(%s, %s) = %v, want %v", + tt.x, tt.y, got.ToString(), want.ToString(), + ) } + } +} + +func TestExp_LargeExponent(t *testing.T) { + tests := []struct { + name string + base string + exponent string + expected string + }{ + { + name: "2^129", + base: "2", + exponent: "680564733841876926926749214863536422912", + expected: "0", + }, + { + name: "2^193", + base: "2", + exponent: "12379400392853802746563808384000000000000000000", + expected: "0", + }, + } - got := &Uint{} - got.Exp(x, y) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + base := MustFromDecimal(tt.base) + exponent := MustFromDecimal(tt.exponent) + expected := MustFromDecimal(tt.expected) - if got.Neq(want) { - t.Errorf("Exp(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } + result := new(Uint).Exp(base, exponent) + + if result.Neq(expected) { + t.Errorf( + "Test %s failed. Expected %s, got %s", + tt.name, expected.ToString(), result.ToString(), + ) + } + }) } } diff --git a/examples/gno.land/p/demo/uint256/bitwise_test.gno b/examples/gno.land/p/demo/uint256/bitwise_test.gno index aba89edfabf..3561629fd94 100644 --- a/examples/gno.land/p/demo/uint256/bitwise_test.gno +++ b/examples/gno.land/p/demo/uint256/bitwise_test.gno @@ -37,11 +37,14 @@ func TestOr(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).Or(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("Or(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).Or(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "Or(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -93,11 +96,14 @@ func TestAnd(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).And(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("And(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).And(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "And(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -126,11 +132,14 @@ func TestNot(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).Not(&tc.x) - if *res != tc.want { - t.Errorf("Not(%s) = %s, want %s", tc.x.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).Not(&tt.x) + if *res != tt.want { + t.Errorf( + "Not(%s) = %s, want %s", + tt.x.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -182,11 +191,14 @@ func TestAndNot(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).AndNot(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("AndNot(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).AndNot(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "AndNot(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -238,11 +250,14 @@ func TestXor(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - res := new(Uint).Xor(&tc.x, &tc.y) - if *res != tc.want { - t.Errorf("Xor(%s, %s) = %s, want %s", tc.x.ToString(), tc.y.ToString(), res.ToString(), (tc.want).ToString()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := new(Uint).Xor(&tt.x, &tt.y) + if *res != tt.want { + t.Errorf( + "Xor(%s, %s) = %s, want %s", + tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + ) } }) } @@ -272,26 +287,31 @@ func TestLsh(t *testing.T) { {"31337", 193, "393411074163624830192644266310117284962799025126338899061243904"}, {"31337", 255, "57896044618658097711785492504343953926634992332820282019728792003956564819968"}, {"31337", 256, "0"}, - } + // 64 < n < 128 + {"1", 65, "36893488147419103232"}, + {"31337", 100, "39724366859352024754702188346867712"}, - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + // 128 < n < 192 + {"1", 129, "680564733841876926926749214863536422912"}, + {"31337", 150, "44725660946326664792723507424638829088826130956288"}, - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } + // 192 < n < 256 + {"1", 193, "12554203470773361527671578846415332832204710888928069025792"}, + {"31337", 200, "50356617492943978264658466087695012475238275216171379079839219712"}, - got := &Uint{} - got.Lsh(x, tc.y) + // n > 256 + {"1", 257, "0"}, + {"31337", 300, "0"}, + } + + for _, tt := range tests { + x := MustFromDecimal(tt.x) + want := MustFromDecimal(tt.want) + + got := new(Uint).Lsh(x, tt.y) if got.Neq(want) { - t.Errorf("Lsh(%s, %d) = %s, want %s", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Lsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) } } } @@ -319,26 +339,85 @@ func TestRsh(t *testing.T) { {"196705537081812415096322133155058642481399512563169449530621952", 192, "31337"}, {"10663428532201448629551770073089320442396672", 128, "31337"}, {"578065619037836218990592", 64, "31337"}, + {twoPow256Sub1, 256, "0"}, + // outliers + {"340282366920938463463374607431768211455", 129, "0"}, + {"18446744073709551615", 65, "0"}, + {twoPow256Sub1, 1, "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, + + // n > 256 + {"1", 257, "0"}, + {"31337", 300, "0"}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) + + want := MustFromDecimal(tt.want) + got := new(Uint).Rsh(x, tt.y) - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue + if got.Neq(want) { + t.Errorf("Rsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) } + } +} + +func TestSRsh(t *testing.T) { + tests := []struct { + x string + y uint + want string + }{ + // Positive numbers (behaves like Rsh) + {"0x0", 0, "0x0"}, + {"0x0", 1, "0x0"}, + {"0x1", 0, "0x1"}, + {"0x1", 1, "0x0"}, + {"0x31337", 0, "0x31337"}, + {"0x31337", 4, "0x3133"}, + {"0x31337", 8, "0x313"}, + {"0x31337", 16, "0x3"}, + {"0x10000000000000000", 64, "0x1"}, // 2^64 >> 64 - got := &Uint{} - got.Rsh(x, tc.y) + // // Numbers with MSB set (negative numbers in two's complement) + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 1, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 4, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 64, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 128, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 192, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 255, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, - if got.Neq(want) { - t.Errorf("Rsh(%s, %d) = %s, want %s", tc.x, tc.y, got.ToString(), want.ToString()) + // Large positive number close to max value + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 1, "0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2, "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 64, "0x7fffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 128, "0x7fffffffffffffffffffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 192, "0x7fffffffffffffff"}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 255, "0x0"}, + + // Specific cases + {"0x8000000000000000000000000000000000000000000000000000000000000000", 1, "0xc000000000000000000000000000000000000000000000000000000000000000"}, + {"0x8000000000000000000000000000000000000000000000000000000000000001", 1, "0xc000000000000000000000000000000000000000000000000000000000000000"}, + + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 65, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 127, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 129, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 193, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, + + // n > 256 + {"0x1", 257, "0x0"}, + {"0x31337", 300, "0x0"}, + } + + for _, tt := range tests { + x := MustFromHex(tt.x) + want := MustFromHex(tt.want) + + got := new(Uint).SRsh(x, tt.y) + + if !got.Eq(want) { + t.Errorf("SRsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) } } } diff --git a/examples/gno.land/p/demo/uint256/cmp_test.gno b/examples/gno.land/p/demo/uint256/cmp_test.gno index 930079f70f0..51c9e70d9a7 100644 --- a/examples/gno.land/p/demo/uint256/cmp_test.gno +++ b/examples/gno.land/p/demo/uint256/cmp_test.gno @@ -5,6 +5,39 @@ import ( "testing" ) +func TestSign(t *testing.T) { + tests := []struct { + input *Uint + expected int + }{ + { + input: NewUint(0), + expected: 0, + }, + { + input: NewUint(1), + expected: 1, + }, + { + input: NewUint(0x7fffffffffffffff), + expected: 1, + }, + { + input: NewUint(0x8000000000000000), + expected: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.input.ToString(), func(t *testing.T) { + result := tt.input.Sign() + if result != tt.expected { + t.Errorf("Sign() = %d; want %d", result, tt.expected) + } + }) + } +} + func TestCmp(t *testing.T) { tests := []struct { x, y string @@ -20,17 +53,8 @@ func TestCmp(t *testing.T) { } for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } + x := MustFromDecimal(tc.x) + y := MustFromDecimal(tc.y) got := x.Cmp(y) if got != tc.want { @@ -49,16 +73,12 @@ func TestIsZero(t *testing.T) { {"10", false}, } - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + for _, tt := range tests { + x := MustFromDecimal(tt.x) got := x.IsZero() - if got != tc.want { - t.Errorf("IsZero(%s) = %v, want %v", tc.x, got, tc.want) + if got != tt.want { + t.Errorf("IsZero(%s) = %v, want %v", tt.x, got, tt.want) } } } @@ -77,31 +97,53 @@ func TestLtUint64(t *testing.T) { } for _, tc := range tests { - var x *Uint - var err error - - if strings.HasPrefix(tc.x, "0x") { - x, err = FromHex(tc.x) - if err != nil { - t.Error(err) - continue - } - } else { - x, err = FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - } + x := parseTestString(t, tc.x) got := x.LtUint64(tc.y) - if got != tc.want { t.Errorf("LtUint64(%s, %d) = %v, want %v", tc.x, tc.y, got, tc.want) } } } +func TestUint_GtUint64(t *testing.T) { + tests := []struct { + name string + z string + n uint64 + want bool + }{ + { + name: "z > n", + z: "1", + n: 0, + want: true, + }, + { + name: "z < n", + z: "18446744073709551615", + n: 0xFFFFFFFFFFFFFFFF, + want: false, + }, + { + name: "z == n", + z: "18446744073709551615", + n: 0xFFFFFFFFFFFFFFFF, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + z := MustFromDecimal(tt.z) + + if got := z.GtUint64(tt.n); got != tt.want { + t.Errorf("Uint.GtUint64() = %v, want %v", got, tt.want) + } + }) + } +} + func TestSGT(t *testing.T) { x := MustFromHex("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe") y := MustFromHex("0x0") @@ -127,37 +169,83 @@ func TestEq(t *testing.T) { {"0xffffffffffffffff", "18446744073709551615", true}, {"0x10000000000000000", "18446744073709551616", true}, {"0", "0", true}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, + {twoPow256Sub1, twoPow256Sub1, true}, } - for i, tc := range tests { - var x *Uint - var err error + for _, tt := range tests { + x := parseTestString(t, tt.x) - if strings.HasPrefix(tc.x, "0x") { - x, err = FromHex(tc.x) - if err != nil { - t.Error(err) - continue - } - } else { - x, err = FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } + y, err := FromDecimal(tt.y) + if err != nil { + t.Error(err) + continue } - y, err := FromDecimal(tc.y) + got := x.Eq(y) + + if got != tt.want { + t.Errorf("Eq(%s, %s) = %v, want %v", tt.x, tt.y, got, tt.want) + } + } +} + +func TestUint_Lte(t *testing.T) { + tests := []struct { + z, x string + want bool + }{ + {"10", "20", true}, + {"20", "10", false}, + {"10", "10", true}, + {"0", "0", true}, + } + + for _, tt := range tests { + z, err := FromDecimal(tt.z) if err != nil { t.Error(err) continue } + x, err := FromDecimal(tt.x) + if err != nil { + t.Error(err) + continue + } + if got := z.Lte(x); got != tt.want { + t.Errorf("Uint.Lte(%v, %v) = %v, want %v", tt.z, tt.x, got, tt.want) + } + } +} - got := x.Eq(y) +func TestUint_Gte(t *testing.T) { + tests := []struct { + z, x string + want bool + }{ + {"20", "10", true}, + {"10", "20", false}, + {"10", "10", true}, + {"0", "0", true}, + } - if got != tc.want { - t.Errorf("Eq(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) + for _, tt := range tests { + z := parseTestString(t, tt.z) + x := parseTestString(t, tt.x) + + if got := z.Gte(x); got != tt.want { + t.Errorf("Uint.Gte(%v, %v) = %v, want %v", tt.z, tt.x, got, tt.want) } } } + +func parseTestString(_ *testing.T, s string) *Uint { + var x *Uint + + if strings.HasPrefix(s, "0x") { + x = MustFromHex(s) + } else { + x = MustFromDecimal(s) + } + + return x +} diff --git a/examples/gno.land/p/demo/uint256/conversion_test.gno b/examples/gno.land/p/demo/uint256/conversion_test.gno index ee3aad0f819..0ea20158be4 100644 --- a/examples/gno.land/p/demo/uint256/conversion_test.gno +++ b/examples/gno.land/p/demo/uint256/conversion_test.gno @@ -14,18 +14,18 @@ func TestIsUint64(t *testing.T) { {"0x10000000000000000", false}, } - for _, tc := range tests { - x := MustFromHex(tc.x) + for _, tt := range tests { + x := MustFromHex(tt.x) got := x.IsUint64() - if got != tc.want { - t.Errorf("IsUint64(%s) = %v, want %v", tc.x, got, tc.want) + if got != tt.want { + t.Errorf("IsUint64(%s) = %v, want %v", tt.x, got, tt.want) } } } func TestDec(t *testing.T) { - testCases := []struct { + tests := []struct { name string z Uint want string @@ -43,16 +43,133 @@ func TestDec(t *testing.T) { { name: "max possible value", z: Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, - want: "115792089237316195423570985008687907853269984665640564039457584007913129639935", + want: twoPow256Sub1, }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := tc.z.Dec() - if result != tc.want { - t.Errorf("Dec(%v) = %s, want %s", tc.z, result, tc.want) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.z.Dec() + if result != tt.want { + t.Errorf("Dec(%v) = %s, want %s", tt.z, result, tt.want) } }) } } + +func TestUint_Scan(t *testing.T) { + tests := []struct { + name string + input interface{} + want *Uint + wantErr bool + }{ + { + name: "nil", + input: nil, + want: NewUint(0), + }, + { + name: "valid scientific notation", + input: "1e4", + want: NewUint(10000), + }, + { + name: "valid decimal string", + input: "12345", + want: NewUint(12345), + }, + { + name: "valid byte slice", + input: []byte("12345"), + want: NewUint(12345), + }, + { + name: "invalid string", + input: "invalid", + wantErr: true, + }, + { + name: "out of range", + input: "115792089237316195423570985008687907853269984665640564039457584007913129639936", // 2^256 + wantErr: true, + }, + { + name: "unsupported type", + input: 123, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + z := new(Uint) + err := z.Scan(tt.input) + + if tt.wantErr { + if err == nil { + t.Errorf("Scan() error = %v, wantErr %v", err, tt.wantErr) + } + } else { + if err != nil { + t.Errorf("Scan() error = %v, wantErr %v", err, tt.wantErr) + } + if !z.Eq(tt.want) { + t.Errorf("Scan() = %v, want %v", z, tt.want) + } + } + }) + } +} + +func TestSetBytes(t *testing.T) { + tests := []struct { + input []byte + expected string + }{ + {[]byte{}, "0"}, + {[]byte{0x01}, "1"}, + {[]byte{0x12, 0x34}, "4660"}, + {[]byte{0x12, 0x34, 0x56}, "1193046"}, + {[]byte{0x12, 0x34, 0x56, 0x78}, "305419896"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a}, "78187493530"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "20015998343868"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "5124095576030430"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "1311768467463790320"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12}, "335812727670730321938"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34}, "85968058283706962416180"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56}, "22007822920628982378542166"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78}, "5634002667681019488906794616"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a}, "1442304682926340989160139421850"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "369229998829143293224995691993788"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "94522879700260683065598897150409950"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "24197857203266734864793317670504947440"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12}, "6194651444036284125387089323649266544658"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34}, "1585830769673288736099094866854212235432500"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56}, "405972677036361916441368285914678332270720086"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78}, "103929005321308650608990281194157653061304342136"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a}, "26605825362255014555901511985704359183693911586970"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "6811091292737283726310787068340315951025641366264508"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "1743639370940744633935561489495120883462564189763714270"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "446371678960830626287503741310750946166416432579510853360"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12}, "114271149813972640329600957775552242218602606740354778460178"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34}, "29253414352376995924377845190541374007962267325530823285805620"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56}, "7488874074208510956640728368778591746038340435335890761166238806"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78}, "1917151762997378804900026462407319486985815151445988034858557134456"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a}, "490790851327328974054406774376273788668368678770172936923790626420890"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}, "125642457939796217357928134240326089899102381765164271852490400363748028"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde}, "32164469232587831643629602365523479014170209731882053594237542493119495390"}, + {[]byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, "8234104123542484900769178205574010627627573691361805720124810878238590820080"}, + // over 32 bytes (last 32 bytes are used) + {append([]byte{0xff}, []byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}...), "8234104123542484900769178205574010627627573691361805720124810878238590820080"}, + } + + for _, test := range tests { + z := new(Uint) + z.SetBytes(test.input) + expected := MustFromDecimal(test.expected) + if z.Cmp(expected) != 0 { + t.Errorf("SetBytes(%x) = %s, expected %s", test.input, z.ToString(), test.expected) + } + } +} diff --git a/examples/gno.land/p/demo/uint256/uint256.gno b/examples/gno.land/p/demo/uint256/uint256.gno index 80da0ba882b..3d183362992 100644 --- a/examples/gno.land/p/demo/uint256/uint256.gno +++ b/examples/gno.land/p/demo/uint256/uint256.gno @@ -5,6 +5,7 @@ package uint256 import ( "errors" "math/bits" + "strconv" ) const ( @@ -143,10 +144,10 @@ func (z *Uint) fromDecimal(bs string) error { if remaining <= 0 { return nil // Done } else if remaining > 19 { - num, err = parseUint(bs[remaining-19:remaining], 10, 64) + num, err = strconv.ParseUint(bs[remaining-19:remaining], 10, 64) } else { // Final round - num, err = parseUint(bs, 10, 64) + num, err = strconv.ParseUint(bs, 10, 64) } if err != nil { return err diff --git a/examples/gno.land/p/demo/uint256/uint256_test.gno b/examples/gno.land/p/demo/uint256/uint256_test.gno new file mode 100644 index 00000000000..0089af15c66 --- /dev/null +++ b/examples/gno.land/p/demo/uint256/uint256_test.gno @@ -0,0 +1,127 @@ +package uint256 + +import ( + "testing" +) + +func TestSetAllOne(t *testing.T) { + z := Zero() + z.SetAllOne() + if z.ToString() != twoPow256Sub1 { + t.Errorf("Expected all ones, got %s", z.ToString()) + } +} + +func TestByte(t *testing.T) { + tests := []struct { + input string + position uint64 + expected byte + }{ + {"0x1000000000000000000000000000000000000000000000000000000000000000", 0, 16}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0, 255}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 31, 255}, + } + + for i, tt := range tests { + z, _ := FromHex(tt.input) + n := NewUint(tt.position) + result := z.Byte(n) + + if result.arr[0] != uint64(tt.expected) { + t.Errorf("Test case %d failed. Input: %s, Position: %d, Expected: %d, Got: %d", + i, tt.input, tt.position, tt.expected, result.arr[0]) + } + + // check other array elements are 0 + if result.arr[1] != 0 || result.arr[2] != 0 || result.arr[3] != 0 { + t.Errorf("Test case %d failed. Non-zero values in upper bytes", i) + } + } + + // overflow + z, _ := FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + n := NewUint(32) + result := z.Byte(n) + + if !result.IsZero() { + t.Errorf("Expected zero for position >= 32, got %v", result) + } +} + +func TestBitLen(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"0x0", 0}, + {"0x1", 1}, + {"0xff", 8}, + {"0x100", 9}, + {"0xffff", 16}, + {"0x10000", 17}, + {"0xffffffffffffffff", 64}, + {"0x10000000000000000", 65}, + {"0xffffffffffffffffffffffffffffffff", 128}, + {"0x100000000000000000000000000000000", 129}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 256}, + } + + for i, tt := range tests { + z, _ := FromHex(tt.input) + result := z.BitLen() + + if result != tt.expected { + t.Errorf("Test case %d failed. Input: %s, Expected: %d, Got: %d", + i, tt.input, tt.expected, result) + } + } +} + +func TestByteLen(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"0x0", 0}, + {"0x1", 1}, + {"0xff", 1}, + {"0x100", 2}, + {"0xffff", 2}, + {"0x10000", 3}, + {"0xffffffffffffffff", 8}, + {"0x10000000000000000", 9}, + {"0xffffffffffffffffffffffffffffffff", 16}, + {"0x100000000000000000000000000000000", 17}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32}, + } + + for i, tt := range tests { + z, _ := FromHex(tt.input) + result := z.ByteLen() + + if result != tt.expected { + t.Errorf("Test case %d failed. Input: %s, Expected: %d, Got: %d", + i, tt.input, tt.expected, result) + } + } +} + +func TestClone(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"0x1", "1"}, + {"0x100", "256"}, + {"0x10000000000000000", "18446744073709551616"}, + } + + for _, tt := range tests { + z, _ := FromHex(tt.input) + result := z.Clone() + if result.ToString() != tt.expected { + t.Errorf("Test %s failed. Expected %s, got %s", tt.input, tt.expected, result.ToString()) + } + } +} diff --git a/examples/gno.land/p/demo/uint256/utils.gno b/examples/gno.land/p/demo/uint256/utils.gno index 969728f3369..bcc7bb283e0 100644 --- a/examples/gno.land/p/demo/uint256/utils.gno +++ b/examples/gno.land/p/demo/uint256/utils.gno @@ -1,63 +1,5 @@ package uint256 -// lower(c) is a lower-case letter if and only if -// c is either that lower-case letter or the equivalent upper-case letter. -// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. -// Note that lower of non-letters can produce other non-letters. -func lower(c byte) byte { - return c | ('x' - 'X') -} - -// underscoreOK reports whether the underscores in s are allowed. -// Checking them in this one function lets all the parsers skip over them simply. -// Underscore must appear only between digits or between a base prefix and a digit. -func underscoreOK(s string) bool { - // saw tracks the last character (class) we saw: - // ^ for beginning of number, - // 0 for a digit or base prefix, - // _ for an underscore, - // ! for none of the above. - saw := '^' - i := 0 - - // Optional sign. - if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { - s = s[1:] - } - - // Optional base prefix. - hex := false - if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { - i = 2 - saw = '0' // base prefix counts as a digit for "underscore as digit separator" - hex = lower(s[1]) == 'x' - } - - // Number proper. - for ; i < len(s); i++ { - // Digits are always okay. - if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { - saw = '0' - continue - } - // Underscore must follow digit. - if s[i] == '_' { - if saw != '0' { - return false - } - saw = '_' - continue - } - // Underscore must also be followed by digit. - if saw == '_' { - return false - } - // Saw non-digit, non-underscore. - saw = '!' - } - return saw != '_' -} - func checkNumberS(input string) error { const fn = "UnmarshalText" l := len(input) @@ -76,105 +18,3 @@ func checkNumberS(input string) error { } return nil } - -// ParseUint is like ParseUint but for unsigned numbers. -// -// A sign prefix is not permitted. -func parseUint(s string, base int, bitSize int) (uint64, error) { - const fnParseUint = "ParseUint" - - if s == "" { - return 0, errSyntax(fnParseUint, s) - } - - base0 := base == 0 - - s0 := s - switch { - case 2 <= base && base <= 36: - // valid base; nothing to do - - case base == 0: - // Look for octal, hex prefix. - base = 10 - if s[0] == '0' { - switch { - case len(s) >= 3 && lower(s[1]) == 'b': - base = 2 - s = s[2:] - case len(s) >= 3 && lower(s[1]) == 'o': - base = 8 - s = s[2:] - case len(s) >= 3 && lower(s[1]) == 'x': - base = 16 - s = s[2:] - default: - base = 8 - s = s[1:] - } - } - - default: - return 0, errInvalidBase(fnParseUint, base) - } - - if bitSize == 0 { - bitSize = uintSize - } else if bitSize < 0 || bitSize > 64 { - return 0, errInvalidBitSize(fnParseUint, bitSize) - } - - // Cutoff is the smallest number such that cutoff*base > maxUint64. - // Use compile-time constants for common cases. - var cutoff uint64 - switch base { - case 10: - cutoff = MaxUint64/10 + 1 - case 16: - cutoff = MaxUint64/16 + 1 - default: - cutoff = MaxUint64/uint64(base) + 1 - } - - maxVal := uint64(1)<= byte(base) { - return 0, errSyntax(fnParseUint, s0) - } - - if n >= cutoff { - // n*base overflows - return maxVal, errRange(fnParseUint, s0) - } - n *= uint64(base) - - n1 := n + uint64(d) - if n1 < n || n1 > maxVal { - // n+d overflows - return maxVal, errRange(fnParseUint, s0) - } - n = n1 - } - - if underscores && !underscoreOK(s0) { - return 0, errSyntax(fnParseUint, s0) - } - - return n, nil -} From d9617858b3bf9fa94961e0d556cca516cc962414 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Thu, 24 Oct 2024 01:42:43 +0900 Subject: [PATCH 39/64] test(stdlibs/io): add additional test (#2898) # Description Fixed a failing test in the io package. Additionally, I activated some previously commented-out tests by bypassing the need for `os.CreateTemp` using `bytes.Buffer`.
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
    --------- Co-authored-by: Morgan Bazalgette --- gnovm/stdlibs/io/export_test.gno | 12 -- gnovm/stdlibs/io/io_test.gno | 208 ++++++++++++++++++++----------- gnovm/stdlibs/io/multi_test.gno | 61 +++++---- 3 files changed, 167 insertions(+), 114 deletions(-) delete mode 100644 gnovm/stdlibs/io/export_test.gno diff --git a/gnovm/stdlibs/io/export_test.gno b/gnovm/stdlibs/io/export_test.gno deleted file mode 100644 index 6204ffc4591..00000000000 --- a/gnovm/stdlibs/io/export_test.gno +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2020 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 io - -// exported for test -var ( - ErrInvalidWrite = errInvalidWrite - ErrWhence = errWhence - ErrOffset = errOffset -) diff --git a/gnovm/stdlibs/io/io_test.gno b/gnovm/stdlibs/io/io_test.gno index a7533a87799..4915982057b 100644 --- a/gnovm/stdlibs/io/io_test.gno +++ b/gnovm/stdlibs/io/io_test.gno @@ -1,4 +1,4 @@ -package io_test +package io // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -8,7 +8,6 @@ import ( "bytes" "errors" "fmt" - "io" "strings" "testing" ) @@ -16,8 +15,8 @@ import ( // A version of bytes.Buffer without ReadFrom and WriteTo type Buffer struct { bytes.Buffer - io.ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom. - io.WriterTo // conflicts with and hides bytes.Buffer's WriterTo. + ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom. + WriterTo // conflicts with and hides bytes.Buffer's WriterTo. } // Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN. @@ -26,7 +25,7 @@ func TestCopy(t *testing.T) { rb := new(Buffer) wb := new(Buffer) rb.WriteString("hello, world.") - io.Copy(wb, rb) + Copy(wb, rb) if wb.String() != "hello, world." { t.Errorf("Copy did not work properly") } @@ -36,12 +35,12 @@ func TestCopyNegative(t *testing.T) { rb := new(Buffer) wb := new(Buffer) rb.WriteString("hello") - io.Copy(wb, &io.LimitedReader{R: rb, N: -1}) + Copy(wb, &LimitedReader{R: rb, N: -1}) if wb.String() != "" { t.Errorf("Copy on LimitedReader with N<0 copied data") } - io.CopyN(wb, rb, -1) + CopyN(wb, rb, -1) if wb.String() != "" { t.Errorf("CopyN with N<0 copied data") } @@ -51,7 +50,7 @@ func TestCopyBuffer(t *testing.T) { rb := new(Buffer) wb := new(Buffer) rb.WriteString("hello, world.") - io.CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest. + CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest. if wb.String() != "hello, world." { t.Errorf("CopyBuffer did not work properly") } @@ -61,7 +60,7 @@ func TestCopyBufferNil(t *testing.T) { rb := new(Buffer) wb := new(Buffer) rb.WriteString("hello, world.") - io.CopyBuffer(wb, rb, nil) // Should allocate a buffer. + CopyBuffer(wb, rb, nil) // Should allocate a buffer. if wb.String() != "hello, world." { t.Errorf("CopyBuffer did not work properly") } @@ -71,7 +70,7 @@ func TestCopyReadFrom(t *testing.T) { rb := new(Buffer) wb := new(bytes.Buffer) // implements ReadFrom. rb.WriteString("hello, world.") - io.Copy(wb, rb) + Copy(wb, rb) if wb.String() != "hello, world." { t.Errorf("Copy did not work properly") } @@ -81,7 +80,7 @@ func TestCopyWriteTo(t *testing.T) { rb := new(bytes.Buffer) // implements WriteTo. wb := new(Buffer) rb.WriteString("hello, world.") - io.Copy(wb, rb) + Copy(wb, rb) if wb.String() != "hello, world." { t.Errorf("Copy did not work properly") } @@ -93,7 +92,7 @@ type writeToChecker struct { writeToCalled bool } -func (wt *writeToChecker) WriteTo(w io.Writer) (int64, error) { +func (wt *writeToChecker) WriteTo(w Writer) (int64, error) { wt.writeToCalled = true return wt.Buffer.WriteTo(w) } @@ -105,7 +104,7 @@ func TestCopyPriority(t *testing.T) { rb := new(writeToChecker) wb := new(bytes.Buffer) rb.WriteString("hello, world.") - io.Copy(wb, rb) + Copy(wb, rb) if wb.String() != "hello, world." { t.Errorf("Copy did not work properly") } else if !rb.writeToCalled { @@ -135,7 +134,7 @@ func (w errWriter) Write([]byte) (int, error) { func TestCopyReadErrWriteErr(t *testing.T) { er, ew := errors.New("readError"), errors.New("writeError") r, w := zeroErrReader{err: er}, errWriter{err: ew} - n, err := io.Copy(w, r) + n, err := Copy(w, r) if n != 0 || err != ew { t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err) } @@ -145,7 +144,7 @@ func TestCopyN(t *testing.T) { rb := new(Buffer) wb := new(Buffer) rb.WriteString("hello, world.") - io.CopyN(wb, rb, 5) + CopyN(wb, rb, 5) if wb.String() != "hello" { t.Errorf("CopyN did not work properly") } @@ -155,7 +154,7 @@ func TestCopyNReadFrom(t *testing.T) { rb := new(Buffer) wb := new(bytes.Buffer) // implements ReadFrom. rb.WriteString("hello") - io.CopyN(wb, rb, 5) + CopyN(wb, rb, 5) if wb.String() != "hello" { t.Errorf("CopyN did not work properly") } @@ -165,7 +164,7 @@ func TestCopyNWriteTo(t *testing.T) { rb := new(bytes.Buffer) // implements WriteTo. wb := new(Buffer) rb.WriteString("hello, world.") - io.CopyN(wb, rb, 5) + CopyN(wb, rb, 5) if wb.String() != "hello" { t.Errorf("CopyN did not work properly") } @@ -178,7 +177,7 @@ func BenchmarkCopyNSmall(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - io.CopyN(buf, rd, 512) + CopyN(buf, rd, 512) rd.Reset(bs) } } @@ -190,13 +189,13 @@ func BenchmarkCopyNLarge(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - io.CopyN(buf, rd, 32*1024) + CopyN(buf, rd, 32*1024) rd.Reset(bs) } } type noReadFrom struct { - w io.Writer + w Writer } func (w *noReadFrom) Write(p []byte) (n int, err error) { @@ -215,32 +214,32 @@ func TestCopyNEOF(t *testing.T) { b := new(bytes.Buffer) - n, err := io.CopyN(&noReadFrom{b}, strings.NewReader("foo"), 3) + n, err := CopyN(&noReadFrom{b}, strings.NewReader("foo"), 3) if n != 3 || err != nil { t.Errorf("CopyN(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err) } - n, err = io.CopyN(&noReadFrom{b}, strings.NewReader("foo"), 4) - if n != 3 || err != io.EOF { + n, err = CopyN(&noReadFrom{b}, strings.NewReader("foo"), 4) + if n != 3 || err != EOF { t.Errorf("CopyN(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err) } - n, err = io.CopyN(b, strings.NewReader("foo"), 3) // b has read from + n, err = CopyN(b, strings.NewReader("foo"), 3) // b has read from if n != 3 || err != nil { t.Errorf("CopyN(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err) } - n, err = io.CopyN(b, strings.NewReader("foo"), 4) // b has read from - if n != 3 || err != io.EOF { + n, err = CopyN(b, strings.NewReader("foo"), 4) // b has read from + if n != 3 || err != EOF { t.Errorf("CopyN(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err) } - n, err = io.CopyN(b, wantedAndErrReader{}, 5) + n, err = CopyN(b, wantedAndErrReader{}, 5) if n != 5 || err != nil { t.Errorf("CopyN(bytes.Buffer, wantedAndErrReader, 5) = %d, %v; want 5, nil", n, err) } - n, err = io.CopyN(&noReadFrom{b}, wantedAndErrReader{}, 5) + n, err = CopyN(&noReadFrom{b}, wantedAndErrReader{}, 5) if n != 5 || err != nil { t.Errorf("CopyN(noReadFrom, wantedAndErrReader, 5) = %d, %v; want 5, nil", n, err) } @@ -268,7 +267,7 @@ func (r *dataAndErrorBuffer) Read(p []byte) (n int, err error) { func TestReadAtLeastWithDataAndEOF(t *testing.T) { var rb dataAndErrorBuffer - rb.err = io.EOF + rb.err = EOF testReadAtLeast(t, &rb) } @@ -278,41 +277,41 @@ func TestReadAtLeastWithDataAndError(t *testing.T) { testReadAtLeast(t, &rb) } -func testReadAtLeast(t *testing.T, rb io.ReadWriter) { +func testReadAtLeast(t *testing.T, rb ReadWriter) { rb.Write([]byte("0123")) buf := make([]byte, 2) - n, err := io.ReadAtLeast(rb, buf, 2) + n, err := ReadAtLeast(rb, buf, 2) if err != nil { t.Error(err) } if n != 2 { t.Errorf("expected to have read 2 bytes, got %v", n) } - n, err = io.ReadAtLeast(rb, buf, 4) - if err != io.ErrShortBuffer { - t.Errorf("expected ErrShortBuffer got %v", err) + n, err = ReadAtLeast(rb, buf, 4) + if err != ErrShortBuffer { + t.Errorf("expected `ErrShortBuffer` got %v", err) } if n != 0 { t.Errorf("expected to have read 0 bytes, got %v", n) } - n, err = io.ReadAtLeast(rb, buf, 1) + n, err = ReadAtLeast(rb, buf, 1) if err != nil { t.Error(err) } if n != 2 { t.Errorf("expected to have read 2 bytes, got %v", n) } - n, err = io.ReadAtLeast(rb, buf, 2) - if err != io.EOF { + n, err = ReadAtLeast(rb, buf, 2) + if err != EOF { t.Errorf("expected EOF, got %v", err) } if n != 0 { t.Errorf("expected to have read 0 bytes, got %v", n) } rb.Write([]byte("4")) - n, err = io.ReadAtLeast(rb, buf, 2) - want := io.ErrUnexpectedEOF - if rb, ok := rb.(*dataAndErrorBuffer); ok && rb.err != io.EOF { + n, err = ReadAtLeast(rb, buf, 2) + want := ErrUnexpectedEOF + if rb, ok := rb.(*dataAndErrorBuffer); ok && rb.err != EOF { want = rb.err } if err != want { @@ -323,14 +322,14 @@ func testReadAtLeast(t *testing.T, rb io.ReadWriter) { } } -/* XXX no io.Pipe() no chan +/* XXX no Pipe() no chan func TestTeeReader(t *testing.T) { src := []byte("hello, world") dst := make([]byte, len(src)) rb := bytes.NewBuffer(src) wb := new(bytes.Buffer) - r := io.TeeReader(rb, wb) - if n, err := io.ReadFull(r, dst); err != nil || n != len(src) { + r := TeeReader(rb, wb) + if n, err := ReadFull(r, dst); err != nil || n != len(src) { t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src)) } if !bytes.Equal(dst, src) { @@ -339,14 +338,14 @@ func TestTeeReader(t *testing.T) { if !bytes.Equal(wb.Bytes(), src) { t.Errorf("bytes written = %q want %q", wb.Bytes(), src) } - if n, err := r.Read(dst); n != 0 || err != io.EOF { + if n, err := r.Read(dst); n != 0 || err != EOF { t.Errorf("r.Read at EOF = %d, %v want 0, EOF", n, err) } rb = bytes.NewBuffer(src) - pr, pw := io.Pipe() + pr, pw := Pipe() pr.Close() - r = io.TeeReader(rb, pw) - if n, err := io.ReadFull(r, dst); n != 0 || err != io.ErrClosedPipe { + r = TeeReader(rb, pw) + if n, err := ReadFull(r, dst); n != 0 || err != ErrClosedPipe { t.Errorf("closed tee: ReadFull(r, dst) = %d, %v; want 0, EPIPE", n, err) } } @@ -363,22 +362,22 @@ func TestSectionReader_ReadAt(t *testing.T) { exp string err error }{ - {data: "", off: 0, n: 10, bufLen: 2, at: 0, exp: "", err: io.EOF}, + {data: "", off: 0, n: 10, bufLen: 2, at: 0, exp: "", err: EOF}, {data: dat, off: 0, n: len(dat), bufLen: 0, at: 0, exp: "", err: nil}, - {data: dat, off: len(dat), n: 1, bufLen: 1, at: 0, exp: "", err: io.EOF}, + {data: dat, off: len(dat), n: 1, bufLen: 1, at: 0, exp: "", err: EOF}, {data: dat, off: 0, n: len(dat) + 2, bufLen: len(dat), at: 0, exp: dat, err: nil}, {data: dat, off: 0, n: len(dat), bufLen: len(dat) / 2, at: 0, exp: dat[:len(dat)/2], err: nil}, {data: dat, off: 0, n: len(dat), bufLen: len(dat), at: 0, exp: dat, err: nil}, {data: dat, off: 0, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[2 : 2+len(dat)/2], err: nil}, {data: dat, off: 3, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[5 : 5+len(dat)/2], err: nil}, {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 - 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: nil}, - {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: io.EOF}, - {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: io.EOF}, - {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: io.EOF}, + {data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: EOF}, + {data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: EOF}, + {data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: EOF}, } for i, tt := range tests { r := strings.NewReader(tt.data) - s := io.NewSectionReader(r, int64(tt.off), int64(tt.n)) + s := NewSectionReader(r, int64(tt.off), int64(tt.n)) buf := make([]byte, tt.bufLen) if n, err := s.ReadAt(buf, int64(tt.at)); n != len(tt.exp) || string(buf[:n]) != tt.exp || err != tt.err { t.Fatalf("%d: ReadAt(%d) = %q, %v; expected %q, %v", i, tt.at, buf[:n], err, tt.exp, tt.err) @@ -389,9 +388,9 @@ func TestSectionReader_ReadAt(t *testing.T) { func TestSectionReader_Seek(t *testing.T) { // Verifies that NewSectionReader's Seeker behaves like bytes.NewReader (which is like strings.NewReader) br := bytes.NewReader([]byte("foo")) - sr := io.NewSectionReader(br, 0, int64(len("foo"))) + sr := NewSectionReader(br, 0, int64(len("foo"))) - for _, whence := range []int{io.SeekStart, io.SeekCurrent, io.SeekEnd} { + for _, whence := range []int{SeekStart, SeekCurrent, SeekEnd} { for offset := int64(-3); offset <= 4; offset++ { brOff, brErr := br.Seek(offset, whence) srOff, srErr := sr.Seek(offset, whence) @@ -403,13 +402,13 @@ func TestSectionReader_Seek(t *testing.T) { } // And verify we can just seek past the end and get an EOF - got, err := sr.Seek(100, io.SeekStart) + got, err := sr.Seek(100, SeekStart) if err != nil || got != 100 { t.Errorf("Seek = %v, %v; want 100, nil", got, err) } n, err := sr.Read(make([]byte, 10)) - if n != 0 || err != io.EOF { + if n != 0 || err != EOF { t.Errorf("Read = %v, %v; want 0, EOF", n, err) } } @@ -425,7 +424,7 @@ func TestSectionReader_Size(t *testing.T) { for _, tt := range tests { r := strings.NewReader(tt.data) - sr := io.NewSectionReader(r, 0, int64(len(tt.data))) + sr := NewSectionReader(r, 0, int64(len(tt.data))) if got := sr.Size(); got != tt.want { t.Errorf("Size = %v; want %v", got, tt.want) } @@ -443,11 +442,11 @@ func (w largeWriter) Write(p []byte) (int, error) { } func TestCopyLargeWriter(t *testing.T) { - want := io.ErrInvalidWrite + want := errInvalidWrite rb := new(Buffer) wb := largeWriter{} rb.WriteString("hello, world.") - if _, err := io.Copy(wb, rb); err != want { + if _, err := Copy(wb, rb); err != want { t.Errorf("Copy error: got %v, want %v", err, want) } @@ -455,7 +454,7 @@ func TestCopyLargeWriter(t *testing.T) { rb = new(Buffer) wb = largeWriter{err: want} rb.WriteString("hello, world.") - if _, err := io.Copy(wb, rb); err != want { + if _, err := Copy(wb, rb); err != want { t.Errorf("Copy error: got %v, want %v", err, want) } } @@ -463,18 +462,18 @@ func TestCopyLargeWriter(t *testing.T) { func TestNopCloserWriterToForwarding(t *testing.T) { for _, tc := range [...]struct { Name string - r io.Reader + r Reader }{ - {"not a WriterTo", io.Reader(nil)}, + {"not a WriterTo", Reader(nil)}, {"a WriterTo", struct { - io.Reader - io.WriterTo + Reader + WriterTo }{}}, } { - nc := io.NopCloser(tc.r) + nc := NopCloser(tc.r) - _, expected := tc.r.(io.WriterTo) - _, got := nc.(io.WriterTo) + _, expected := tc.r.(WriterTo) + _, got := nc.(WriterTo) if expected != got { t.Errorf("NopCloser incorrectly forwards WriterTo for %s, got %t want %t", tc.Name, got, expected) } @@ -496,9 +495,9 @@ func TestNopCloserWriterToForwarding(t *testing.T) { // for _, whence := range []int{-3, -2, -1, 3, 4, 5} { // var offset int64 = 0 // gotOff, gotErr := w.Seek(offset, whence) -// if gotOff != 0 || gotErr != ErrWhence { +// if gotOff != 0 || gotErr != errWhence { // t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", -// whence, offset, gotOff, gotErr, 0, ErrWhence) +// whence, offset, gotOff, gotErr, 0, errWhence) // } // } // }) @@ -508,7 +507,7 @@ func TestNopCloserWriterToForwarding(t *testing.T) { // for _, whence := range []int{SeekStart, SeekCurrent} { // for offset := int64(-3); offset < 0; offset++ { // gotOff, gotErr := w.Seek(offset, whence) -// if gotOff != 0 || gotErr != ErrOffset { +// if gotOff != 0 || gotErr != errOffset { // t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", // whence, offset, gotOff, gotErr, 0, ErrOffset) // } @@ -540,3 +539,70 @@ func TestNopCloserWriterToForwarding(t *testing.T) { // } // }) // } + +// TODO: The original test uses `os.CreateTemp`, but here +// to work around it by using `bytes.Buffer`. +// When `os.CreateTemp` is available in the future, we should change the test +// to use the original approach instead of this method. (just un-comment the test above) +func TestOffsetWriter_Seek(t *testing.T) { + buf := new(bytes.Buffer) + w := NewOffsetWriter(testWriterAt{buf}, 0) + + // Should throw error errWhence if whence is not valid + t.Run("errWhence", func(t *testing.T) { + for _, whence := range []int{-3, -2, -1, 3, 4, 5} { + var offset int64 = 0 + gotOff, gotErr := w.Seek(offset, whence) + if gotOff != 0 || gotErr != errWhence { + t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", + whence, offset, gotOff, gotErr, 0, errWhence) + } + } + }) + + // Should throw error errOffset if offset is negative + t.Run("errOffset", func(t *testing.T) { + for _, whence := range []int{SeekStart, SeekCurrent} { + for offset := int64(-3); offset < 0; offset++ { + gotOff, gotErr := w.Seek(offset, whence) + if gotOff != 0 || gotErr != errOffset { + t.Errorf("For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, %v)", + whence, offset, gotOff, gotErr, 0, errOffset) + } + } + } + }) + + t.Run("normal", func(t *testing.T) { + tests := []struct { + offset int64 + whence int + returnOff int64 + }{ + {whence: SeekStart, offset: 1, returnOff: 1}, + {whence: SeekStart, offset: 2, returnOff: 2}, + {whence: SeekStart, offset: 3, returnOff: 3}, + {whence: SeekCurrent, offset: 1, returnOff: 4}, + {whence: SeekCurrent, offset: 2, returnOff: 6}, + {whence: SeekCurrent, offset: 3, returnOff: 9}, + } + for idx, tt := range tests { + gotOff, gotErr := w.Seek(tt.offset, tt.whence) + if gotOff != tt.returnOff || gotErr != nil { + t.Errorf("%d:: For whence %d, offset %d, OffsetWriter.Seek got: (%d, %v), want: (%d, )", + idx+1, tt.whence, tt.offset, gotOff, gotErr, tt.returnOff) + } + } + }) +} + +type testWriterAt struct { + buf *bytes.Buffer +} + +func (w testWriterAt) WriteAt(p []byte, off int64) (n int, err error) { + if int64(w.buf.Len()) < off+int64(len(p)) { + w.buf.Grow(int(off + int64(len(p)) - int64(w.buf.Len()))) + } + return copy(w.buf.Bytes()[off:], p), nil +} diff --git a/gnovm/stdlibs/io/multi_test.gno b/gnovm/stdlibs/io/multi_test.gno index 31345279318..8932ace2e59 100644 --- a/gnovm/stdlibs/io/multi_test.gno +++ b/gnovm/stdlibs/io/multi_test.gno @@ -1,4 +1,4 @@ -package io_test +package io // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -8,7 +8,6 @@ import ( "bytes" "crypto/sha1" "fmt" - "io" "strings" "testing" ) @@ -18,14 +17,14 @@ type Stringer interface { } func TestMultiReader(t *testing.T) { - var mr io.Reader + var mr Reader var buf []byte nread := 0 withFooBar := func(tests func()) { r1 := strings.NewReader("foo ") r2 := strings.NewReader("") r3 := strings.NewReader("bar") - mr = io.MultiReader(r1, r2, r3) + mr = MultiReader(r1, r2, r3) buf = make([]byte, 20) tests() } @@ -51,13 +50,13 @@ func TestMultiReader(t *testing.T) { expectRead(2, "fo", nil) expectRead(5, "o ", nil) expectRead(5, "bar", nil) - expectRead(5, "", io.EOF) + expectRead(5, "", EOF) }) withFooBar(func() { expectRead(4, "foo ", nil) expectRead(1, "b", nil) expectRead(3, "ar", nil) - expectRead(1, "", io.EOF) + expectRead(1, "", EOF) }) withFooBar(func() { expectRead(5, "foo ", nil) @@ -68,7 +67,7 @@ func TestMultiWriter(t *testing.T) { sink := new(bytes.Buffer) // Hide bytes.Buffer's WriteString method: testMultiWriter(t, struct { - io.Writer + Writer Stringer }{sink, sink}) } @@ -83,11 +82,11 @@ func TestMultiWriter_String(t *testing.T) { func TestMultiWriter_WriteStringSingleAlloc(t *testing.T) { var sink1, sink2 bytes.Buffer type simpleWriter struct { // hide bytes.Buffer's WriteString - io.Writer + Writer } - mw := io.MultiWriter(simpleWriter{&sink1}, simpleWriter{&sink2}) + mw := MultiWriter(simpleWriter{&sink1}, simpleWriter{&sink2}) allocs := int(testing.AllocsPerRun2(1000, func() { - io.WriteString(mw, "foo") + WriteString(mw, "foo") })) if allocs != 1 { t.Errorf("num allocations = %d; want 1", allocs) @@ -108,24 +107,24 @@ func (c *writeStringChecker) Write(p []byte) (n int, err error) { func TestMultiWriter_StringCheckCall(t *testing.T) { var c writeStringChecker - mw := io.MultiWriter(&c) - io.WriteString(mw, "foo") + mw := MultiWriter(&c) + WriteString(mw, "foo") if !c.called { t.Error("did not see WriteString call to writeStringChecker") } } func testMultiWriter(t *testing.T, sink interface { - io.Writer + Writer Stringer }, ) { sha1 := sha1.New() - mw := io.MultiWriter(sha1, sink) + mw := MultiWriter(sha1, sink) sourceString := "My input text." source := strings.NewReader(sourceString) - written, err := io.Copy(mw, source) + written, err := Copy(mw, source) if written != int64(len(sourceString)) { t.Errorf("short write of %d, not %d", written, len(sourceString)) @@ -183,25 +182,25 @@ func TestMultiWriterSingleChainFlatten(t *testing.T) { func TestMultiWriterError(t *testing.T) { f1 := writerFunc(func(p []byte) (int, error) { - return len(p) / 2, io.ErrShortWrite + return len(p) / 2, ErrShortWrite }) f2 := writerFunc(func(p []byte) (int, error) { t.Errorf("MultiWriter called f2.Write") return len(p), nil }) - w := io.MultiWriter(f1, f2) + w := MultiWriter(f1, f2) n, err := w.Write(make([]byte, 100)) - if n != 50 || err != io.ErrShortWrite { + if n != 50 || err != ErrShortWrite { t.Errorf("Write = %d, %v, want 50, ErrShortWrite", n, err) } } // Test that MultiReader copies the input slice and is insulated from future modification. func TestMultiReaderCopy(t *testing.T) { - slice := []io.Reader{strings.NewReader("hello world")} - r := io.MultiReader(slice...) + slice := []Reader{strings.NewReader("hello world")} + r := MultiReader(slice...) slice[0] = nil - data, err := io.ReadAll(r) + data, err := ReadAll(r) if err != nil || string(data) != "hello world" { t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world") } @@ -210,8 +209,8 @@ func TestMultiReaderCopy(t *testing.T) { // Test that MultiWriter copies the input slice and is insulated from future modification. func TestMultiWriterCopy(t *testing.T) { var buf bytes.Buffer - slice := []io.Writer{&buf} - w := io.MultiWriter(slice...) + slice := []Writer{&buf} + w := MultiWriter(slice...) slice[0] = nil n, err := w.Write([]byte("hello world")) if err != nil || n != 11 { @@ -278,12 +277,12 @@ func (b byteAndEOFReader) Read(p []byte) (n int, err error) { panic("unexpected call") } p[0] = byte(b) - return 1, io.EOF + return 1, EOF } // This used to yield bytes forever; issue 16795. func TestMultiReaderSingleByteWithEOF(t *testing.T) { - got, err := io.ReadAll(io.LimitReader(io.MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10)) + got, err := ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10)) if err != nil { t.Fatal(err) } @@ -297,10 +296,10 @@ func TestMultiReaderSingleByteWithEOF(t *testing.T) { // chain continues to return EOF on its final read, rather than // yielding a (0, EOF). func TestMultiReaderFinalEOF(t *testing.T) { - r := io.MultiReader(bytes.NewReader(nil), byteAndEOFReader('a')) + r := MultiReader(bytes.NewReader(nil), byteAndEOFReader('a')) buf := make([]byte, 2) n, err := r.Read(buf) - if n != 1 || err != io.EOF { + if n != 1 || err != EOF { t.Errorf("got %v, %v; want 1, EOF", n, err) } } @@ -343,21 +342,21 @@ func TestInterleavedMultiReader(t *testing.T) { r1 := strings.NewReader("123") r2 := strings.NewReader("45678") - mr1 := io.MultiReader(r1, r2) - mr2 := io.MultiReader(mr1) + mr1 := MultiReader(r1, r2) + mr2 := MultiReader(mr1) buf := make([]byte, 4) // Have mr2 use mr1's []Readers. // Consume r1 (and clear it for GC to handle) and consume part of r2. - n, err := io.ReadFull(mr2, buf) + n, err := ReadFull(mr2, buf) if got := string(buf[:n]); got != "1234" || err != nil { t.Errorf(`ReadFull(mr2) = (%q, %v), want ("1234", nil)`, got, err) } // Consume the rest of r2 via mr1. // This should not panic even though mr2 cleared r1. - n, err = io.ReadFull(mr1, buf) + n, err = ReadFull(mr1, buf) if got := string(buf[:n]); got != "5678" || err != nil { t.Errorf(`ReadFull(mr1) = (%q, %v), want ("5678", nil)`, got, err) } From f4c4204c183cd234f3eefa284da1e19110ba712c Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:55:31 -0400 Subject: [PATCH 40/64] feat(gnovm): add 'gno test -print-events' + cleanup machine between tests (#2975) - [x] add `gno test -print-events` flag for unit tests. Props to @r3v4s for his work on #2071 - [x] add `// Events:` support in `_filetests.gno`. - [x] cleanup `gno.Machine` between unit tests (\o/) . Fixes #1982 Closes #2071 Addresses #2007 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .github/workflows/examples.yml | 2 +- .../gno.land/p/demo/ownable/ownable_test.gno | 9 --- .../gno.land/r/demo/event/z1_filetest.gno | 11 ++++ examples/gno.land/r/gnoland/events/events.gno | 9 +-- .../gno.land/r/gnoland/events/events_test.gno | 13 ++-- gnovm/cmd/gno/test.go | 29 ++++++++- .../testdata/gno_test/filetest_events.txtar | 33 ++++++++++ .../testdata/gno_test/multitest_events.txtar | 26 ++++++++ gnovm/tests/file.go | 63 ++++++++++++++++++- 9 files changed, 170 insertions(+), 25 deletions(-) create mode 100644 examples/gno.land/r/demo/event/z1_filetest.gno create mode 100644 gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar create mode 100644 gnovm/cmd/gno/testdata/gno_test/multitest_events.txtar diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 5b3c3c1fbf1..77d40098900 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -47,7 +47,7 @@ jobs: echo "LOG_LEVEL=debug" >> $GITHUB_ENV echo "LOG_PATH_DIR=$LOG_PATH_DIR" >> $GITHUB_ENV - run: go install -v ./gnovm/cmd/gno - - run: go run ./gnovm/cmd/gno test -v ./examples/... + - run: go run ./gnovm/cmd/gno test -v -print-events ./examples/... lint: strategy: fail-fast: false diff --git a/examples/gno.land/p/demo/ownable/ownable_test.gno b/examples/gno.land/p/demo/ownable/ownable_test.gno index a9d97154f45..dee40fa6e1d 100644 --- a/examples/gno.land/p/demo/ownable/ownable_test.gno +++ b/examples/gno.land/p/demo/ownable/ownable_test.gno @@ -33,15 +33,6 @@ func TestNewWithAddress(t *testing.T) { } } -func TestOwner(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(alice)) - - o := New() - expected := alice - got := o.Owner() - uassert.Equal(t, expected, got) -} - func TestTransferOwnership(t *testing.T) { std.TestSetRealm(std.NewUserRealm(alice)) diff --git a/examples/gno.land/r/demo/event/z1_filetest.gno b/examples/gno.land/r/demo/event/z1_filetest.gno new file mode 100644 index 00000000000..1fcfa1a0e4f --- /dev/null +++ b/examples/gno.land/r/demo/event/z1_filetest.gno @@ -0,0 +1,11 @@ +package main + +import "gno.land/r/demo/event" + +func main() { + event.Emit("foo") + event.Emit("bar") +} + +// Events: +// [{"type":"TAG","attrs":[{"key":"key","value":"foo"}],"pkg_path":"gno.land/r/demo/event","func":"Emit"},{"type":"TAG","attrs":[{"key":"key","value":"bar"}],"pkg_path":"gno.land/r/demo/event","func":"Emit"}] diff --git a/examples/gno.land/r/gnoland/events/events.gno b/examples/gno.land/r/gnoland/events/events.gno index 0984edf75a9..baf9ba3d4af 100644 --- a/examples/gno.land/r/gnoland/events/events.gno +++ b/examples/gno.land/r/gnoland/events/events.gno @@ -73,8 +73,7 @@ func AddEvent(name, description, link, location, startTime, endTime string) (str sort.Sort(events) std.Emit(EventAdded, - "id", - e.id, + "id", e.id, ) return id, nil @@ -92,8 +91,7 @@ func DeleteEvent(id string) { events = append(events[:idx], events[idx+1:]...) std.Emit(EventDeleted, - "id", - e.id, + "id", e.id, ) } @@ -142,8 +140,7 @@ func EditEvent(id string, name, description, link, location, startTime, endTime } std.Emit(EventEdited, - "id", - e.id, + "id", e.id, ) } diff --git a/examples/gno.land/r/gnoland/events/events_test.gno b/examples/gno.land/r/gnoland/events/events_test.gno index 357857352d8..1d79b754ee4 100644 --- a/examples/gno.land/r/gnoland/events/events_test.gno +++ b/examples/gno.land/r/gnoland/events/events_test.gno @@ -85,7 +85,8 @@ func TestAddEventErrors(t *testing.T) { } func TestDeleteEvent(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 + std.TestSetOrigCaller(su) + std.TestSetRealm(suRealm) e1Start := parsedTimeNow.Add(time.Hour * 24 * 5) e1End := e1Start.Add(time.Hour * 4) @@ -107,7 +108,8 @@ func TestDeleteEvent(t *testing.T) { } func TestEditEvent(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 + std.TestSetOrigCaller(su) + std.TestSetRealm(suRealm) e1Start := parsedTimeNow.Add(time.Hour * 24 * 5) e1End := e1Start.Add(time.Hour * 4) @@ -136,7 +138,8 @@ func TestEditEvent(t *testing.T) { } func TestInvalidEdit(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 + std.TestSetOrigCaller(su) + std.TestSetRealm(suRealm) uassert.PanicsWithMessage(t, ErrNoSuchID.Error(), func() { EditEvent("123123", "", "", "", "", "", "") @@ -162,9 +165,11 @@ func TestParseTimes(t *testing.T) { } func TestRenderEventWidget(t *testing.T) { - events = nil // remove elements from previous tests - see issue #1982 + std.TestSetOrigCaller(su) + std.TestSetRealm(suRealm) // No events yet + events = nil out, err := RenderEventWidget(1) uassert.NoError(t, err) uassert.Equal(t, out, "No events.") diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index af7fa28a14d..e23f9fa2750 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -21,6 +21,7 @@ import ( gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/gnovm/tests" + teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/random" @@ -35,6 +36,7 @@ type testCfg struct { timeout time.Duration updateGoldenTests bool printRuntimeMetrics bool + printEvents bool withNativeFallback bool } @@ -149,6 +151,13 @@ func (c *testCfg) RegisterFlags(fs *flag.FlagSet) { false, "print runtime metrics (gas, memory, cpu cycles)", ) + + fs.BoolVar( + &c.printEvents, + "print-events", + false, + "print emitted events", + ) } func execTest(cfg *testCfg, args []string, io commands.IO) error { @@ -228,6 +237,7 @@ func gnoTestPkg( rootDir = cfg.rootDir runFlag = cfg.run printRuntimeMetrics = cfg.printRuntimeMetrics + printEvents = cfg.printEvents stdin = io.In() stdout = io.Out() @@ -295,7 +305,7 @@ func gnoTestPkg( m.Alloc = gno.NewAllocator(maxAllocTx) } m.RunMemPackage(memPkg, true) - err := runTestFiles(m, tfiles, memPkg.Name, verbose, printRuntimeMetrics, runFlag, io) + err := runTestFiles(m, tfiles, memPkg.Name, verbose, printRuntimeMetrics, printEvents, runFlag, io) if err != nil { errs = multierr.Append(errs, err) } @@ -329,7 +339,7 @@ func gnoTestPkg( memPkg.Path = memPkg.Path + "_test" m.RunMemPackage(memPkg, true) - err := runTestFiles(m, ifiles, testPkgName, verbose, printRuntimeMetrics, runFlag, io) + err := runTestFiles(m, ifiles, testPkgName, verbose, printRuntimeMetrics, printEvents, runFlag, io) if err != nil { errs = multierr.Append(errs, err) } @@ -419,6 +429,7 @@ func runTestFiles( pkgName string, verbose bool, printRuntimeMetrics bool, + printEvents bool, runFlag string, io commands.IO, ) (errs error) { @@ -448,10 +459,24 @@ func runTestFiles( m.RunFiles(n) for _, test := range testFuncs.Tests { + // cleanup machine between tests + tests.CleanupMachine(m) + testFuncStr := fmt.Sprintf("%q", test.Name) eval := m.Eval(gno.Call("runtest", testFuncStr)) + if printEvents { + events := m.Context.(*teststd.TestExecContext).EventLogger.Events() + if events != nil { + res, err := json.Marshal(events) + if err != nil { + panic(err) + } + io.ErrPrintfln("EVENTS: %s", string(res)) + } + } + ret := eval[0].GetString() if ret == "" { err := errors.New("failed to execute unit test: %q", test.Name) diff --git a/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar b/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar new file mode 100644 index 00000000000..5e0520a2e85 --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar @@ -0,0 +1,33 @@ +# Test with a valid _filetest.gno file + +gno test -print-events . + +! stdout .+ +stderr 'ok \. \d\.\d\ds' + +gno test -print-events -v . + +! stdout .+ +stderr '=== RUN file/valid_filetest.gno' +stderr '--- PASS: file/valid_filetest.gno \(\d\.\d\ds\)' +stderr 'ok \. \d\.\d\ds' + +-- valid.gno -- +package valid + +-- valid_filetest.gno -- +package main + +import "std" + +func main() { + println("test") + std.Emit("EventA") + std.Emit("EventB", "keyA", "valA") +} + +// Output: +// test + +// Events: +// [{"type":"EventA","attrs":[],"pkg_path":"","func":"main"},{"type":"EventB","attrs":[{"key":"keyA","value":"valA"}],"pkg_path":"","func":"main"}] diff --git a/gnovm/cmd/gno/testdata/gno_test/multitest_events.txtar b/gnovm/cmd/gno/testdata/gno_test/multitest_events.txtar new file mode 100644 index 00000000000..321c790561a --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_test/multitest_events.txtar @@ -0,0 +1,26 @@ +# Test with a valid _test.gno file + +gno test -print-events . + +! stdout .+ +stderr 'EVENTS: \[{\"type\":\"EventA\",\"attrs\":\[\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestA\"}\]' +stderr 'EVENTS: \[{\"type\":\"EventB\",\"attrs\":\[{\"key\":\"keyA\",\"value\":\"valA\"}\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestB\"},{\"type\":\"EventC\",\"attrs\":\[{\"key\":\"keyD\",\"value\":\"valD\"}\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestB\"}\]' +stderr 'ok \. \d\.\d\ds' + +-- valid.gno -- +package valid + +-- valid_test.gno -- +package valid + +import "testing" +import "std" + +func TestA(t *testing.T) { + std.Emit("EventA") +} + +func TestB(t *testing.T) { + std.Emit("EventB", "keyA", "valA") + std.Emit("EventC", "keyD", "valD") +} diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index f45beffe648..5449adc01d2 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -2,6 +2,7 @@ package tests import ( "bytes" + "encoding/json" "fmt" "go/ast" "go/parser" @@ -54,7 +55,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(ugnot.ValueString(200_000_000)).Add(send) // >= send. banker := newTestBanker(pkgAddr.Bech32(), pkgCoins) ctx := stdlibs.ExecContext{ ChainID: "dev", @@ -74,6 +75,19 @@ func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext { } } +// CleanupMachine can be called during two tests while reusing the same Machine instance. +func CleanupMachine(m *gno.Machine) { + prevCtx := m.Context.(*teststd.TestExecContext) + prevSend := prevCtx.OrigSend + + newCtx := TestContext("", prevCtx.OrigSend) + pkgCoins := std.MustParseCoins(ugnot.ValueString(200_000_000)).Add(prevSend) // >= send. + banker := newTestBanker(prevCtx.OrigPkgAddr, pkgCoins) + newCtx.OrigPkgAddr = prevCtx.OrigPkgAddr + newCtx.Banker = banker + m.Context = newCtx +} + type runFileTestOptions struct { nativeLibs bool logger loggerFunc @@ -110,7 +124,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { opt(&f) } - directives, pkgPath, resWanted, errWanted, rops, stacktraceWanted, maxAlloc, send, preWanted := wantedFromComment(path) + directives, pkgPath, resWanted, errWanted, rops, eventsWanted, stacktraceWanted, maxAlloc, send, preWanted := wantedFromComment(path) if pkgPath == "" { pkgPath = "main" } @@ -347,6 +361,45 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { } } } + case "Events": + // panic if got unexpected error + + if pnc != nil { + if tv, ok := pnc.(*gno.TypedValue); ok { + panic(fmt.Sprintf("fail on %s: got unexpected error: %s", path, tv.Sprint(m))) + } else { // happens on 'unknown import path ...' + panic(fmt.Sprintf("fail on %s: got unexpected error: %v", path, pnc)) + } + } + // check result + events := m.Context.(*teststd.TestExecContext).EventLogger.Events() + evtjson, err := json.Marshal(events) + if err != nil { + panic(err) + } + evtstr := trimTrailingSpaces(string(evtjson)) + if evtstr != eventsWanted { + if f.syncWanted { + // write output to file. + replaceWantedInPlace(path, "Events", evtstr) + } else { + // panic so tests immediately fail (for now). + if eventsWanted == "" { + panic(fmt.Sprintf("fail on %s: got unexpected events: %s", path, evtstr)) + } else { + diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(eventsWanted), + B: difflib.SplitLines(evtstr), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) + } + } + } case "Realm": // panic if got unexpected error if pnc != nil { @@ -448,7 +501,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { return nil } -func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, stacktrace string, maxAlloc int64, send std.Coins, pre string) { +func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, events, stacktrace string, maxAlloc int64, send std.Coins, pre string) { fset := token.NewFileSet() f, err2 := parser.ParseFile(fset, p, nil, parser.ParseComments) if err2 != nil { @@ -490,6 +543,10 @@ 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, "Events:\n") { + events = strings.TrimPrefix(text, "Events:\n") + events = strings.TrimSpace(events) + directives = append(directives, "Events") } else if strings.HasPrefix(text, "Preprocessed:\n") { pre = strings.TrimPrefix(text, "Preprocessed:\n") pre = strings.TrimSpace(pre) From a2e5c3dda1ce2ef6bdc980e2cabc26ff7ed873d7 Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 23 Oct 2024 21:18:38 +0200 Subject: [PATCH 41/64] ci: remove unused goreleaser files, ignore chain/ tags (#3004) I don't know how to test this, but I think this may fix it. @ajnavarro do you have a separate repo / access to the pro token and can see if this configuration works? I removed the other config files as they weren't used, and the `nightly:` section as I don't think it's parsed, anyway: it doesn't exist in the goreleaser schema. --- .github/goreleaser-master.yaml | 503 ------------------ .github/goreleaser-nightly.yaml | 502 ----------------- .github/goreleaser.yaml | 30 +- .../{nightlies.yml => releaser-nightly.yml} | 3 +- 4 files changed, 19 insertions(+), 1019 deletions(-) delete mode 100644 .github/goreleaser-master.yaml delete mode 100644 .github/goreleaser-nightly.yaml rename .github/workflows/{nightlies.yml => releaser-nightly.yml} (99%) diff --git a/.github/goreleaser-master.yaml b/.github/goreleaser-master.yaml deleted file mode 100644 index bca52615db8..00000000000 --- a/.github/goreleaser-master.yaml +++ /dev/null @@ -1,503 +0,0 @@ -project_name: gno - -before: - hooks: - - go mod tidy - -builds: - - id: gno - main: ./gnovm/cmd/gno - binary: gno - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - - id: gnoland - main: ./gno.land/cmd/gnoland - binary: gnoland - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - - id: gnokey - main: ./gno.land/cmd/gnokey - binary: gnokey - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - - id: gnoweb - main: ./gno.land/cmd/gnoweb - binary: gnoweb - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 -gomod: - proxy: true - -archives: - # https://goreleaser.com/customization/archive/ - - files: - # Standard Release Files - - LICENSE.md - - README.md - -signs: - - cmd: cosign - env: - - COSIGN_EXPERIMENTAL=1 - certificate: "${artifact}.pem" - args: - - sign-blob - - "--output-certificate=${certificate}" - - "--output-signature=${signature}" - - "${artifact}" - - "--yes" # needed on cosign 2.0.0+ - artifacts: checksum - output: true - -dockers: - # https://goreleaser.com/customization/docker/ - - # gno - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}:master-amd64" - build_flag_templates: - - "--target=gno" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}:master-arm64v8" - build_flag_templates: - - "--target=gno" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}:master-armv6" - build_flag_templates: - - "--target=gno" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}:master-armv7" - build_flag_templates: - - "--target=gno" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - # gnoland - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-amd64" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-arm64v8" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-armv6" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-armv7" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - # gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-amd64" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-arm64v8" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-armv6" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-armv7" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - # gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-amd64" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-arm64v8" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-armv6" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-armv7" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - -docker_manifests: - # https://goreleaser.com/customization/docker_manifest/ - - # gno - - name_template: ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}:master - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}:master-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}:master-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}:master-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}:master-armv7 - - # gnoland - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-amd64 - - 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:master - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:master-armv7 - - # gnokey - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-amd64 - - 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:master - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:master-armv7 - - # gnoweb - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-amd64 - - 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:master - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:master-armv7 - -docker_signs: - - cmd: cosign - env: - - COSIGN_EXPERIMENTAL=1 - artifacts: images - output: true - args: - - "sign" - - "${artifact}" - - "--yes" # needed on cosign 2.0.0+ - -checksum: - name_template: "checksums.txt" - -changelog: - sort: asc - -source: - enabled: true - -sboms: - - artifacts: archive - - id: source # Two different sbom configurations need two different IDs - artifacts: source - -release: - draft: true - replace_existing_draft: true - prerelease: auto - make_latest: false - mode: append - footer: | - ### Container Images - - You can find all docker images at: - - https://github.com/orgs/gnolang/packages?repo_name={{ .ProjectName }} - -nightly: - tag_name: master - publish_release: true - keep_single_release: true - name_template: "{{ incpatch .Version }}-{{ .ShortCommit }}-master" \ No newline at end of file diff --git a/.github/goreleaser-nightly.yaml b/.github/goreleaser-nightly.yaml deleted file mode 100644 index 3dac915b7cd..00000000000 --- a/.github/goreleaser-nightly.yaml +++ /dev/null @@ -1,502 +0,0 @@ -project_name: gno - -before: - hooks: - - go mod tidy - -builds: - - id: gno - main: ./gnovm/cmd/gno - binary: gno - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - - id: gnoland - main: ./gno.land/cmd/gnoland - binary: gnoland - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - - id: gnokey - main: ./gno.land/cmd/gnokey - binary: gnokey - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 - - id: gnoweb - main: ./gno.land/cmd/gnoweb - binary: gnoweb - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - goarch: - - amd64 - - arm64 - - arm - goarm: - - 6 - - 7 -gomod: - proxy: true - -archives: - # https://goreleaser.com/customization/archive/ - - files: - # Standard Release Files - - LICENSE.md - - README.md - -signs: - - cmd: cosign - env: - - COSIGN_EXPERIMENTAL=1 - certificate: "${artifact}.pem" - args: - - sign-blob - - "--output-certificate=${certificate}" - - "--output-signature=${signature}" - - "${artifact}" - - "--yes" # needed on cosign 2.0.0+ - artifacts: checksum - output: true - -dockers: - # https://goreleaser.com/customization/docker/ - - # gno - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}:nightly-amd64" - build_flag_templates: - - "--target=gno" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}:nightly-arm64v8" - build_flag_templates: - - "--target=gno" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}:nightly-armv6" - build_flag_templates: - - "--target=gno" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}:nightly-armv7" - build_flag_templates: - - "--target=gno" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gno - extra_files: - - examples - - gnovm/stdlibs - - gnovm/tests/stdlibs - - # gnoland - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-amd64" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-arm64v8" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-armv6" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-armv7" - build_flag_templates: - - "--target=gnoland" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoland" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoland - extra_files: - - gno.land/genesis/genesis_balances.txt - - gno.land/genesis/genesis_txs.jsonl - - examples - - gnovm/stdlibs - # gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-amd64" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-arm64v8" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-armv6" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-armv7" - build_flag_templates: - - "--target=gnokey" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnokey" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnokey - - # gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: amd64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-amd64" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-amd64" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm64 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-arm64v8" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-arm64v8" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/arm64/v8" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 6 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv6" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-armv6" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - - use: buildx - dockerfile: Dockerfile.release - goos: linux - goarch: arm - goarm: 7 - image_templates: - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-armv7" - - "ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-armv7" - build_flag_templates: - - "--target=gnoweb" - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}/gnoweb" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - ids: - - gnoweb - -docker_manifests: - # https://goreleaser.com/customization/docker_manifest/ - - # gno - - name_template: ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}:{{ .Version }}-armv7 - - name_template: ghcr.io/gnolang/{{ .ProjectName }}:nightly - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}:nightly-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}:nightly-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}:nightly-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}:nightly-armv7 - - # gnoland - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:{{ .Version }}-amd64 - - 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:nightly - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoland:nightly-armv7 - - # gnokey - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:{{ .Version }}-amd64 - - 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:nightly - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnokey:nightly-armv7 - - # gnoweb - - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }} - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }}-amd64 - - 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:nightly - image_templates: - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-amd64 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-arm64v8 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-armv6 - - ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:nightly-armv7 - -docker_signs: - - cmd: cosign - env: - - COSIGN_EXPERIMENTAL=1 - artifacts: images - output: true - args: - - "sign" - - "${artifact}" - - "--yes" # needed on cosign 2.0.0+ - -checksum: - name_template: "checksums.txt" - -changelog: - sort: asc - -source: - enabled: true - -sboms: - - artifacts: archive - - id: source # Two different sbom configurations need two different IDs - artifacts: source - -release: - draft: true - replace_existing_draft: true - prerelease: auto - mode: append - footer: | - ### Container Images - - You can find all docker images at: - - https://github.com/orgs/gnolang/packages?repo_name={{ .ProjectName }} - -nightly: - tag_name: nightly - publish_release: true - keep_single_release: true - name_template: "{{ incpatch .Version }}-{{ .ShortCommit }}-nightly" \ No newline at end of file diff --git a/.github/goreleaser.yaml b/.github/goreleaser.yaml index cd3c62c2ae6..e2a91ef7ea6 100644 --- a/.github/goreleaser.yaml +++ b/.github/goreleaser.yaml @@ -24,8 +24,8 @@ builds: - arm64 - arm goarm: - - 6 - - 7 + - "6" + - "7" - id: gnoland main: ./gno.land/cmd/gnoland binary: gnoland @@ -39,8 +39,8 @@ builds: - arm64 - arm goarm: - - 6 - - 7 + - "6" + - "7" - id: gnokey main: ./gno.land/cmd/gnokey binary: gnokey @@ -54,8 +54,8 @@ builds: - arm64 - arm goarm: - - 6 - - 7 + - "6" + - "7" - id: gnoweb main: ./gno.land/cmd/gnoweb binary: gnoweb @@ -69,8 +69,8 @@ builds: - arm64 - arm goarm: - - 6 - - 7 + - "6" + - "7" - id: gnofaucet dir: ./contribs/gnofaucet binary: gnofaucet @@ -84,8 +84,8 @@ builds: - arm64 - arm goarm: - - 6 - - 7 + - "6" + - "7" - id: gnobro dir: ./contribs/gnodev/cmd/gnobro binary: gnobro @@ -99,8 +99,8 @@ builds: - arm64 - arm goarm: - - 6 - - 7 + - "6" + - "7" gomod: proxy: true @@ -616,7 +616,7 @@ docker_manifests: - 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 - + # gnoweb - name_template: ghcr.io/gnolang/{{ .ProjectName }}/gnoweb:{{ .Version }} image_templates: @@ -704,3 +704,7 @@ nightly: publish_release: true keep_single_release: true name_template: "{{ incpatch .Version }}-{{ .ShortCommit }}-{{ .Env.TAG_VERSION }}" + +git: + ignore_tag_prefixes: + - "chain/" diff --git a/.github/workflows/nightlies.yml b/.github/workflows/releaser-nightly.yml similarity index 99% rename from .github/workflows/nightlies.yml rename to .github/workflows/releaser-nightly.yml index 99f9a406ed1..b53772f5951 100644 --- a/.github/workflows/nightlies.yml +++ b/.github/workflows/releaser-nightly.yml @@ -34,7 +34,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - + - uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro @@ -44,3 +44,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} TAG_VERSION: nightly + From 4927d4b03f961d164fdce01f9bd0ad192b1e60ee Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 23 Oct 2024 22:16:00 +0200 Subject: [PATCH 42/64] ci: fixup goreleaser workflow, again (#3008)
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
    Co-authored-by: Sergio Maria Matone --- .github/goreleaser.yaml | 2 +- .github/workflows/releaser-nightly.yml | 2 +- .github/workflows/releaser.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/goreleaser.yaml b/.github/goreleaser.yaml index e2a91ef7ea6..b5fb07d0578 100644 --- a/.github/goreleaser.yaml +++ b/.github/goreleaser.yaml @@ -703,7 +703,7 @@ nightly: tag_name: nightly publish_release: true keep_single_release: true - name_template: "{{ incpatch .Version }}-{{ .ShortCommit }}-{{ .Env.TAG_VERSION }}" + version_template: "{{ incpatch .Version }}-{{ .ShortCommit }}-{{ .Env.TAG_VERSION }}" git: ignore_tag_prefixes: diff --git a/.github/workflows/releaser-nightly.yml b/.github/workflows/releaser-nightly.yml index b53772f5951..314c25e3580 100644 --- a/.github/workflows/releaser-nightly.yml +++ b/.github/workflows/releaser-nightly.yml @@ -39,7 +39,7 @@ jobs: with: distribution: goreleaser-pro version: ~> v2 - args: release --clean --nightly --config ./.github/goreleaser.yaml + args: release --clean --nightly --skip=validate --snapshot --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 4fb3c279b1f..057951dbf31 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -39,7 +39,7 @@ jobs: with: distribution: goreleaser-pro version: ~> v2 - args: release --clean --config ./.github/goreleaser.yaml + args: release --clean --snapshot --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} From c2aef422c2f38240e3fd53aea212473dad9e996b Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 23 Oct 2024 22:22:30 +0200 Subject: [PATCH 43/64] ci: fix goreleaser ci again again (#3010)
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
    --------- Co-authored-by: Sergio Maria Matone --- .github/workflows/releaser-master.yml | 2 +- .github/workflows/releaser-nightly.yml | 5 ++--- .github/workflows/releaser.yml | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/releaser-master.yml b/.github/workflows/releaser-master.yml index 59dc2ec8705..535cac5d965 100644 --- a/.github/workflows/releaser-master.yml +++ b/.github/workflows/releaser-master.yml @@ -40,7 +40,7 @@ jobs: with: distribution: goreleaser-pro version: ~> v2 - args: release --clean --nightly --config ./.github/goreleaser.yaml + args: release --clean --snapshot --nightly --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} diff --git a/.github/workflows/releaser-nightly.yml b/.github/workflows/releaser-nightly.yml index 314c25e3580..fd4eaa86b0e 100644 --- a/.github/workflows/releaser-nightly.yml +++ b/.github/workflows/releaser-nightly.yml @@ -2,7 +2,7 @@ name: Trigger nightly build on: schedule: - - cron: '0 0 * * 2-6' + - cron: "0 0 * * 2-6" workflow_dispatch: permissions: @@ -39,9 +39,8 @@ jobs: with: distribution: goreleaser-pro version: ~> v2 - args: release --clean --nightly --skip=validate --snapshot --config ./.github/goreleaser.yaml + args: release --clean --nightly --snapshot --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} TAG_VERSION: nightly - diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index 057951dbf31..8bbc9323cad 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -34,12 +34,12 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - + - uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser-pro version: ~> v2 - args: release --clean --snapshot --config ./.github/goreleaser.yaml + args: release --clean --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} From 520195e3747e2c749a100a53adbf7fb30d6edbba Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Wed, 23 Oct 2024 22:24:49 +0200 Subject: [PATCH 44/64] feat(stdlibs/std): prohibit getting Banker from a pure package (#2248) Related to #2192 - Trigger a panic if a p/ attempts to create a banker, but allow interaction with an already instantiated banker from r/. Don't really know if this is the right approach. If you have another idea of how to implement this security check please let me know :)
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
    --------- Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .../gno.land/r/demo/banktest/z_0_filetest.gno | 11 +++++-- .../gno.land/r/demo/banktest/z_1_filetest.gno | 7 ++++- .../gno.land/r/demo/banktest/z_2_filetest.gno | 11 +++++-- .../gno.land/r/demo/banktest/z_3_filetest.gno | 11 +++++-- .../gno.land/r/demo/disperse/z_0_filetest.gno | 4 ++- .../gno.land/r/demo/disperse/z_1_filetest.gno | 4 ++- .../gno.land/r/demo/disperse/z_2_filetest.gno | 4 ++- .../gno.land/r/demo/disperse/z_3_filetest.gno | 4 ++- .../gno.land/r/demo/disperse/z_4_filetest.gno | 4 ++- gnovm/Makefile | 2 +- gnovm/stdlibs/generated.go | 12 ++++++++ gnovm/stdlibs/std/banker.gno | 1 + gnovm/stdlibs/std/native.gno | 1 + gnovm/stdlibs/std/native.go | 7 +++++ gnovm/tests/files/stdbanker_stdlibs.gno | 13 ++++++++ gnovm/tests/stdlibs/generated.go | 30 +++++++++++++++++++ gnovm/tests/stdlibs/std/frame_testing.gno | 3 ++ gnovm/tests/stdlibs/std/std.gno | 1 + gnovm/tests/stdlibs/std/std.go | 4 +++ 19 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 gnovm/tests/files/stdbanker_stdlibs.gno diff --git a/examples/gno.land/r/demo/banktest/z_0_filetest.gno b/examples/gno.land/r/demo/banktest/z_0_filetest.gno index 4ea76bbe17a..61289dfe071 100644 --- a/examples/gno.land/r/demo/banktest/z_0_filetest.gno +++ b/examples/gno.land/r/demo/banktest/z_0_filetest.gno @@ -1,6 +1,11 @@ +// Empty line between the directives is important for them to be parsed +// independently. :facepalm: + +// PKGPATH: gno.land/r/demo/bank1 + // SEND: 100000000ugnot -package main +package bank1 import ( "std" @@ -11,7 +16,7 @@ import ( func main() { // set up main address and banktest addr. banktestAddr := std.DerivePkgAddr("gno.land/r/demo/banktest") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/bank1") std.TestSetOrigCaller(mainaddr) std.TestSetOrigPkgAddr(banktestAddr) @@ -42,7 +47,7 @@ func main() { // main after: 250000000ugnot // ## recent activity // -// * g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4 100000000ugnot sent, 50000000ugnot returned, at 2009-02-13 11:31pm UTC +// * g1tnpdmvrmtgql8fmxgsq9rwtst5hsxahk3f05dk 100000000ugnot sent, 50000000ugnot returned, at 2009-02-13 11:31pm UTC // // ## total deposits // 50000000ugnot diff --git a/examples/gno.land/r/demo/banktest/z_1_filetest.gno b/examples/gno.land/r/demo/banktest/z_1_filetest.gno index 8f9f7647036..39682d26330 100644 --- a/examples/gno.land/r/demo/banktest/z_1_filetest.gno +++ b/examples/gno.land/r/demo/banktest/z_1_filetest.gno @@ -1,4 +1,9 @@ -package main +// Empty line between the directives is important for them to be parsed +// independently. :facepalm: + +// PKGPATH: gno.land/r/demo/bank1 + +package bank1 import ( "std" diff --git a/examples/gno.land/r/demo/banktest/z_2_filetest.gno b/examples/gno.land/r/demo/banktest/z_2_filetest.gno index a0280e0d75b..2dc9c84e767 100644 --- a/examples/gno.land/r/demo/banktest/z_2_filetest.gno +++ b/examples/gno.land/r/demo/banktest/z_2_filetest.gno @@ -1,4 +1,9 @@ -package main +// Empty line between the directives is important for them to be parsed +// independently. :facepalm: + +// PKGPATH: gno.land/r/demo/bank1 + +package bank1 import ( "std" @@ -10,7 +15,7 @@ func main() { banktestAddr := std.DerivePkgAddr("gno.land/r/demo/banktest") // print main balance before. - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/bank1") std.TestSetOrigCaller(mainaddr) banker := std.GetBanker(std.BankerTypeReadonly) @@ -39,7 +44,7 @@ func main() { // main after: 255000000ugnot // ## recent activity // -// * g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4 100000000ugnot sent, 55000000ugnot returned, at 2009-02-13 11:31pm UTC +// * g1tnpdmvrmtgql8fmxgsq9rwtst5hsxahk3f05dk 100000000ugnot sent, 55000000ugnot returned, at 2009-02-13 11:31pm UTC // // ## total deposits // 45000000ugnot diff --git a/examples/gno.land/r/demo/banktest/z_3_filetest.gno b/examples/gno.land/r/demo/banktest/z_3_filetest.gno index ca8717dfcc9..7b6758c3e4f 100644 --- a/examples/gno.land/r/demo/banktest/z_3_filetest.gno +++ b/examples/gno.land/r/demo/banktest/z_3_filetest.gno @@ -1,4 +1,9 @@ -package main +// Empty line between the directives is important for them to be parsed +// independently. :facepalm: + +// PKGPATH: gno.land/r/demo/bank1 + +package bank1 import ( "std" @@ -7,7 +12,7 @@ import ( func main() { banktestAddr := std.DerivePkgAddr("gno.land/r/demo/banktest") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/bank1") std.TestSetOrigCaller(mainaddr) banker := std.GetBanker(std.BankerTypeRealmSend) @@ -17,4 +22,4 @@ func main() { } // Error: -// can only send coins from realm that created banker "g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4", not "g1dv3435088tlrgggf745kaud0ptrkc9v42k8llz" +// can only send coins from realm that created banker "g1tnpdmvrmtgql8fmxgsq9rwtst5hsxahk3f05dk", not "g1dv3435088tlrgggf745kaud0ptrkc9v42k8llz" diff --git a/examples/gno.land/r/demo/disperse/z_0_filetest.gno b/examples/gno.land/r/demo/disperse/z_0_filetest.gno index 62a34cfdf26..e54b34ae3bf 100644 --- a/examples/gno.land/r/demo/disperse/z_0_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_0_filetest.gno @@ -1,3 +1,5 @@ +// PKGPATH: gno.land/r/demo/main + // SEND: 200ugnot package main @@ -10,7 +12,7 @@ import ( func main() { disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/main") std.TestSetOrigPkgAddr(disperseAddr) std.TestSetOrigCaller(mainaddr) diff --git a/examples/gno.land/r/demo/disperse/z_1_filetest.gno b/examples/gno.land/r/demo/disperse/z_1_filetest.gno index 1e042d320f6..62018fe965e 100644 --- a/examples/gno.land/r/demo/disperse/z_1_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_1_filetest.gno @@ -1,3 +1,5 @@ +// PKGPATH: gno.land/r/demo/main + // SEND: 300ugnot package main @@ -10,7 +12,7 @@ import ( func main() { disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/main") std.TestSetOrigPkgAddr(disperseAddr) std.TestSetOrigCaller(mainaddr) diff --git a/examples/gno.land/r/demo/disperse/z_2_filetest.gno b/examples/gno.land/r/demo/disperse/z_2_filetest.gno index 163bb2fc1ab..79e8d81e2b1 100644 --- a/examples/gno.land/r/demo/disperse/z_2_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_2_filetest.gno @@ -1,3 +1,5 @@ +// PKGPATH: gno.land/r/demo/main + // SEND: 300ugnot package main @@ -10,7 +12,7 @@ import ( func main() { disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/main") std.TestSetOrigPkgAddr(disperseAddr) std.TestSetOrigCaller(mainaddr) diff --git a/examples/gno.land/r/demo/disperse/z_3_filetest.gno b/examples/gno.land/r/demo/disperse/z_3_filetest.gno index eabed52fb38..7cb7ffbe71d 100644 --- a/examples/gno.land/r/demo/disperse/z_3_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_3_filetest.gno @@ -1,3 +1,5 @@ +// PKGPATH: gno.land/r/demo/main + // SEND: 300ugnot package main @@ -11,7 +13,7 @@ import ( func main() { disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/main") beneficiary1 := std.Address("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0") beneficiary2 := std.Address("g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c") diff --git a/examples/gno.land/r/demo/disperse/z_4_filetest.gno b/examples/gno.land/r/demo/disperse/z_4_filetest.gno index ebf4bed4473..4dafb780e83 100644 --- a/examples/gno.land/r/demo/disperse/z_4_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_4_filetest.gno @@ -1,3 +1,5 @@ +// PKGPATH: gno.land/r/demo/main + // SEND: 300ugnot package main @@ -11,7 +13,7 @@ import ( func main() { disperseAddr := std.DerivePkgAddr("gno.land/r/demo/disperse") - mainaddr := std.DerivePkgAddr("main") + mainaddr := std.DerivePkgAddr("gno.land/r/demo/main") beneficiary1 := std.Address("g1dmt3sa5ucvecxuhf3j6ne5r0e3z4x7h6c03xc0") beneficiary2 := std.Address("g1akeqsvhucjt8gf5yupyzjxsjd29wv8fayng37c") diff --git a/gnovm/Makefile b/gnovm/Makefile index 5ff3af9c253..d27395d9cd1 100644 --- a/gnovm/Makefile +++ b/gnovm/Makefile @@ -54,7 +54,7 @@ lint: .PHONY: fmt fmt: - go run ./cmd/gno fmt $(GNOFMT_FLAGS) ./stdlibs/... + go run ./cmd/gno fmt $(GNOFMT_FLAGS) ./stdlibs/... ./tests/stdlibs/... $(rundep) mvdan.cc/gofumpt $(GOFMT_FLAGS) . .PHONY: imports diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index b0788fc6d1b..a2d82b0bc60 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -720,6 +720,18 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "std", + "assertCallerIsRealm", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + libs_std.X_assertCallerIsRealm( + m, + ) + }, + }, { "std", "setParamString", diff --git a/gnovm/stdlibs/std/banker.gno b/gnovm/stdlibs/std/banker.gno index 2b94292bd7e..5412b73281c 100644 --- a/gnovm/stdlibs/std/banker.gno +++ b/gnovm/stdlibs/std/banker.gno @@ -65,6 +65,7 @@ func (b BankerType) String() string { // GetBanker returns a new Banker, with its capabilities matching the given // [BankerType]. func GetBanker(bt BankerType) Banker { + assertCallerIsRealm() if bt >= maxBanker { panic("invalid banker type") } diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index 22a16fc18d1..5421e231de2 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -65,3 +65,4 @@ func getRealm(height int) (address string, pkgPath string) func derivePkgAddr(pkgPath string) string func encodeBech32(prefix string, bz [20]byte) string func decodeBech32(addr string) (prefix string, bz [20]byte, ok bool) +func assertCallerIsRealm() diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index f185a52f249..3fe5fbb9889 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -158,6 +158,13 @@ func X_decodeBech32(addr string) (prefix string, bytes [20]byte, ok bool) { return prefix, [20]byte(bz), true } +func X_assertCallerIsRealm(m *gno.Machine) { + frame := m.Frames[m.NumFrames()-2] + if path := frame.LastPackage.PkgPath; !gno.IsRealmPath(path) { + m.Panic(typedString("caller is not a realm")) + } +} + func typedString(s string) gno.TypedValue { tv := gno.TypedValue{T: gno.StringType} tv.SetString(gno.StringValue(s)) diff --git a/gnovm/tests/files/stdbanker_stdlibs.gno b/gnovm/tests/files/stdbanker_stdlibs.gno new file mode 100644 index 00000000000..d0872dd38e6 --- /dev/null +++ b/gnovm/tests/files/stdbanker_stdlibs.gno @@ -0,0 +1,13 @@ +package main + +import "std" + +func main() { + defer func() { + println(recover()) + }() + std.TestSetRealm(std.NewCodeRealm("gno.land/p/demo/users")) +} + +// Output: +// should only be called for Realms diff --git a/gnovm/tests/stdlibs/generated.go b/gnovm/tests/stdlibs/generated.go index 23bb3cfa594..f3d74e214eb 100644 --- a/gnovm/tests/stdlibs/generated.go +++ b/gnovm/tests/stdlibs/generated.go @@ -296,6 +296,36 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "std", + "isRealm", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + }, + []gno.FieldTypeExpr{ + {Name: gno.N("r0"), Type: gno.X("bool")}, + }, + true, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + + r0 := testlibs_std.X_isRealm( + m, + p0) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, { "testing", "unixNano", diff --git a/gnovm/tests/stdlibs/std/frame_testing.gno b/gnovm/tests/stdlibs/std/frame_testing.gno index 171756c54f5..f9952969497 100644 --- a/gnovm/tests/stdlibs/std/frame_testing.gno +++ b/gnovm/tests/stdlibs/std/frame_testing.gno @@ -8,5 +8,8 @@ func NewUserRealm(user Address) Realm { // NewCodeRealm creates a new realm for a published code realm with the given // pkgPath. func NewCodeRealm(pkgPath string) Realm { + if !isRealm(pkgPath) { + panic("should only be called for Realms") + } return Realm{pkgPath: pkgPath, addr: DerivePkgAddr(pkgPath)} } diff --git a/gnovm/tests/stdlibs/std/std.gno b/gnovm/tests/stdlibs/std/std.gno index f583342ae04..3a56ecc1c47 100644 --- a/gnovm/tests/stdlibs/std/std.gno +++ b/gnovm/tests/stdlibs/std/std.gno @@ -38,3 +38,4 @@ func testSetOrigSend( spentDenom []string, spentAmt []int64) func testIssueCoins(addr string, denom []string, amt []int64) func getRealm(height int) (address string, pkgPath string) +func isRealm(pkgPath string) bool diff --git a/gnovm/tests/stdlibs/std/std.go b/gnovm/tests/stdlibs/std/std.go index 0421f359932..d580572e9c5 100644 --- a/gnovm/tests/stdlibs/std/std.go +++ b/gnovm/tests/stdlibs/std/std.go @@ -173,6 +173,10 @@ func X_getRealm(m *gno.Machine, height int) (address string, pkgPath string) { return string(ctx.OrigCaller), "" } +func X_isRealm(m *gno.Machine, pkgPath string) bool { + return gno.IsRealmPath(pkgPath) +} + func X_testSetOrigSend(m *gno.Machine, sentDenom []string, sentAmt []int64, spentDenom []string, spentAmt []int64, From 287c22ec830a1408f1d3de6319602640d841c7cc Mon Sep 17 00:00:00 2001 From: ltzmaxwell Date: Wed, 23 Oct 2024 23:09:04 -0500 Subject: [PATCH 45/64] fix(gnovm): fix issue with locally re-definition (#3014) closes: https://github.com/gnolang/gno/issues/3013
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
    --------- Co-authored-by: Morgan Bazalgette --- gnovm/pkg/gnolang/preprocess.go | 7 +------ gnovm/tests/files/redefine.gno | 15 +++++++++++++++ gnovm/tests/files/redefine2.gno | 25 +++++++++++++++++++++++++ gnovm/tests/files/redefine3.gno | 13 +++++++++++++ gnovm/tests/files/redefine4.gno | 15 +++++++++++++++ gnovm/tests/files/redefine5.gno | 18 ++++++++++++++++++ gnovm/tests/files/redefine6.gno | 9 +++++++++ 7 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 gnovm/tests/files/redefine.gno create mode 100644 gnovm/tests/files/redefine2.gno create mode 100644 gnovm/tests/files/redefine3.gno create mode 100644 gnovm/tests/files/redefine4.gno create mode 100644 gnovm/tests/files/redefine5.gno create mode 100644 gnovm/tests/files/redefine6.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index e1dc3671333..04cc83b54f0 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -157,7 +157,6 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { switch n := n.(type) { case *AssignStmt: if n.Op == DEFINE { - var defined bool for _, lx := range n.Lhs { nx := lx.(*NameExpr) ln := nx.Name @@ -165,16 +164,12 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { continue } if !isLocallyDefined2(last, ln) { - // if loop extern, will change to + // if loop extern, will promote to // NameExprTypeHeapDefine later. nx.Type = NameExprTypeDefine last.Predefine(false, ln) - defined = true } } - if !defined { - panic(fmt.Sprintf("nothing defined in assignment %s", n.String())) - } } case *ImportDecl: nx := &n.NameExpr diff --git a/gnovm/tests/files/redefine.gno b/gnovm/tests/files/redefine.gno new file mode 100644 index 00000000000..62eea61f25e --- /dev/null +++ b/gnovm/tests/files/redefine.gno @@ -0,0 +1,15 @@ +package main + +var ss = []int{1, 2, 3} + +func main() { + for _, s := range ss { + s := s + println(s) + } +} + +// Output: +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/redefine2.gno b/gnovm/tests/files/redefine2.gno new file mode 100644 index 00000000000..b0621fe2a03 --- /dev/null +++ b/gnovm/tests/files/redefine2.gno @@ -0,0 +1,25 @@ +package main + +var testTable = []struct { + name string +}{ + { + "one", + }, + { + "two", + }, +} + +func main() { + + for _, testCase := range testTable { + testCase := testCase + + println(testCase.name) + } +} + +// Output: +// one +// two diff --git a/gnovm/tests/files/redefine3.gno b/gnovm/tests/files/redefine3.gno new file mode 100644 index 00000000000..7a2d0859f5c --- /dev/null +++ b/gnovm/tests/files/redefine3.gno @@ -0,0 +1,13 @@ +package main + +func main() { + for i := 0; i < 3; i++ { + i := i + println(i) + } +} + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/redefine4.gno b/gnovm/tests/files/redefine4.gno new file mode 100644 index 00000000000..db310fae3c2 --- /dev/null +++ b/gnovm/tests/files/redefine4.gno @@ -0,0 +1,15 @@ +package main + +func main() { + a := 1 + b := 3 + println(a, b) // prints 1 3 + + // Re-declaration of 'a' is allowed because 'c' is a new variable + a, c := 2, 5 + println(a, c) // prints 2 5 +} + +// Output: +// 1 3 +// 2 5 diff --git a/gnovm/tests/files/redefine5.gno b/gnovm/tests/files/redefine5.gno new file mode 100644 index 00000000000..9637df913f0 --- /dev/null +++ b/gnovm/tests/files/redefine5.gno @@ -0,0 +1,18 @@ +package main + +func main() { + a := 1 + println(a) // prints 1 + + if true { + a := 2 // valid: new scope inside the if statement + println(a) // prints 2 + } + + println(a) // prints 1: outer variable is unchanged +} + +// Output: +// 1 +// 2 +// 1 diff --git a/gnovm/tests/files/redefine6.gno b/gnovm/tests/files/redefine6.gno new file mode 100644 index 00000000000..ff5ca97d063 --- /dev/null +++ b/gnovm/tests/files/redefine6.gno @@ -0,0 +1,9 @@ +package main + +func main() { + a, b := 1, 2 + a, b := 3, 4 +} + +// Error: +// files/redefine6.gno:5:2: no new variables on left side of := From a478348dec4f07373dfefd614ef8682e34ae7278 Mon Sep 17 00:00:00 2001 From: Nemanja Aleksic Date: Fri, 25 Oct 2024 09:32:37 -0500 Subject: [PATCH 46/64] chore: remove CODEOWNERS (#3022) Remove all teams and individuals in CODEOWNERS Related to https://github.com/gnolang/gno/issues/3019 --- .github/CODEOWNERS | 97 ---------------------------------------------- 1 file changed, 97 deletions(-) delete mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index bafaa70301b..00000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,97 +0,0 @@ -# CODEOWNERS: https://help.github.com/articles/about-codeowners/ - -# Primary repo maintainers. -* @gnolang/tech-staff - -# Tendermint2. -/tm2/ @jaekwon @moul @piux2 @zivkovicmilos -/tm2/pkg/crypto/ @jaekwon @moul @gnolang/security -/tm2/pkg/crypto/keys/client/ @jaekwon @gnolang/security -/tm2/pkg/db/ @ajnavarro -# TODO: add per package exceptions -# ... - -# Docs & Content. -/docs/ @moul -/docs/**.md @gnolang/devrels -/docs/**.gif @gnolang/devrels -/docs/Makefile @gnolang/devrels -/README.md @moul @gnolang/devrels -/**/README.md @gnolang/devrels -/.gitpod.yml @gnolang/devrels - -# Gno examples and default contracts. -/examples/ @gnolang/tech-staff @gnolang/devrels -/examples/gno.land/p/demo/ @gnolang/tech-staff @gnolang/devrels -/examples/gno.land/p/demo/avl/ @jaekwon -/examples/gno.land/p/demo/bf/ @moul -/examples/gno.land/p/demo/blog/ @gnolang/devrels -/examples/gno.land/p/demo/boardsv2/ @ilgooz @jeronimoalbi @moul -/examples/gno.land/p/demo/cford32/ @thehowl -/examples/gno.land/p/demo/memeland/ @leohhhn -/examples/gno.land/p/demo/seqid/ @thehowl -/examples/gno.land/p/demo/ownable/ @leohhhn -/examples/gno.land/p/demo/pausable/ @leohhhn -/examples/gno.land/p/demo/svg/ @moul -/examples/gno.land/p/demo/tamagotchi/ @moul -/examples/gno.land/p/demo/ui/ @moul -/examples/gno.land/r/demo/ @gnolang/tech-staff @gnolang/devrels -/examples/gno.land/r/demo/art/ @moul -/examples/gno.land/r/demo/boardsv2/ @ilgooz @jeronimoalbi @moul -/examples/gno.land/r/demo/memeland/ @leohhhn -/examples/gno.land/r/demo/tamagotchi/ @moul -/examples/gno.land/r/demo/userbook/ @leohhhn -/examples/gno.land/r/gnoland/ @moul -/examples/gno.land/r/sys/ @moul -/examples/gno.land/r/jaekwon/ @jaekwon -/examples/gno.land/r/manfred/ @moul - -# Gno.land. -/gno.land/ @moul @zivkovicmilos -/gno.land/cmd/genesis/ @zivkovicmilos -/gno.land/cmd/gnokey/ @jaekwon @moul @gfanton -/gno.land/cmd/gnoland/ @zivkovicmilos @gnolang/devops -/gno.land/cmd/gnoweb/ @gfanton @thehowl @alexiscolin -/gno.land/pkg/gnoclient/ @zivkovicmilos @leohhhn @gfanton -/gno.land/pkg/gnoland/ @zivkovicmilos @gfanton -/gno.land/pkg/keyscli/ @jaekwon @moul @gfanton -/gno.land/pkg/log/ @zivkovicmilos @gfanton -/gno.land/pkg/sdk/vm/ @moul @gfanton @thehowl -/gno.land/pkg/integration/ @gfanton -/gno.land/genesis/ @moul -#... - -# GnoVM/Gnolang. -/gnovm/ @jaekwon @moul @piux2 @thehowl -/gnovm/stdlibs/ @thehowl -/gnovm/tests/ @jaekwon @thehowl @mvertes -/gnovm/cmd/gno/ @moul @thehowl -/gnovm/pkg/gnolang/ @jaekwon @moul @piux2 -/gnovm/pkg/doc/ @thehowl -/gnovm/pkg/repl/ @mvertes @ajnavarro -/gnovm/pkg/gnomod/ @thehowl -/gnovm/pkg/gnoenv/ @gfanton -/gnovm/pkg/transpiler/ @thehowl -/gnovm/pkg/integration/ @gfanton - -# Contribs -/contribs/ @gnolang/tech-staff -/contribs/gnodev/ @gfanton -/contribs/gnokeykc/ @moul -/contribs/gnomd/ @moul - -# Misc -/misc/ @gnolang/tech-staff -/misc/loop/ @moul @gnolang/devops -/misc/deployments/ @moul @gnolang/devops -/misc/genstd/ @thehowl - -# Special files. -/PLAN.md @jaekwon @moul -/PHILOSOPHY.md @jaekwon -/CONTRIBUTING.md @jaekwon @moul @gnolang/tech-staff -/LICENSE.md @jaekwon -/.github/ @moul @gnolang/tech-staff -/.github/workflows @ajnavarro @moul -/.github/CODEOWNERS @jaekwon @moul -/go.mod @gnolang/tech-staff # no unnecessary dependencies From 0b2c67ed3883bd04d0a03eb8c85ce218616099c2 Mon Sep 17 00:00:00 2001 From: Morgan Date: Fri, 25 Oct 2024 13:26:12 -0500 Subject: [PATCH 47/64] fix(gnolang): ensure complete Uverse initialization (#2997) Fixes #2067. UverseNode now distinguishes when it's uninitialized, initializing and initialized. In combination with calling Uverse() at init, we make sure that after package initialization we always have the same result from Uverse() and UverseNode() and we don't have issues like those pointed out in #2067. --- gnovm/pkg/gnolang/gno_test.go | 12 --------- gnovm/pkg/gnolang/preprocess.go | 6 +---- gnovm/pkg/gnolang/uverse.go | 47 ++++++++++++++++++++++++++------- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/gnovm/pkg/gnolang/gno_test.go b/gnovm/pkg/gnolang/gno_test.go index 1f83303023c..3b15c018505 100644 --- a/gnovm/pkg/gnolang/gno_test.go +++ b/gnovm/pkg/gnolang/gno_test.go @@ -404,18 +404,6 @@ func BenchmarkBenchdata(b *testing.B) { name += "_param:" + param } b.Run(name, func(b *testing.B) { - if strings.HasPrefix(name, "matrix.gno_param") { - // CGO_ENABLED=0 go test -bench . -benchmem ./... -short -run=^$ -cpu 1,2 -count=1 ./... - // That is not just exposing test and benchmark traces as output, but these benchmarks are failing - // making the output unparseable: - /* - BenchmarkBenchdata/matrix.gno_param:3 panic: runtime error: index out of range [31] with length 25 [recovered] - panic: runtime error: index out of range [31] with length 25: - ... - */ - b.Skip("it panics causing an error when parsing benchmark results") - } - // Gen template with N and param. var buf bytes.Buffer require.NoError(b, tpl.Execute(&buf, bdataParams{ diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 04cc83b54f0..2d65dfa5cb1 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -734,12 +734,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_BLOCK ----------------------- case *FuncDecl: // retrieve cached function type. + // the type and receiver are already set in predefineNow. ft := getType(&n.Type).(*FuncType) - if n.IsMethod { - // recv/type set @ predefineNow(). - } else { - // type set @ predefineNow(). - } // push func body block. pushInitBlock(n, &last, &stack) diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index d62d4228d68..ba66b27499f 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -61,26 +61,55 @@ var gStringerType = &DeclaredType{ var ( uverseNode *PackageNode uverseValue *PackageValue + uverseInit = uverseUninitialized ) +const ( + uverseUninitialized = iota + uverseInitializing + uverseInitialized +) + +func init() { + // Call Uverse() so we initialize the Uverse node ahead of any calls to the package. + Uverse() +} + const uversePkgPath = ".uverse" -// Always returns a new copy from the latest state of source. +// UverseNode returns the uverse PackageValue. +// If called while initializing the UverseNode itself, it will return an empty +// PackageValue. func Uverse() *PackageValue { - if uverseValue == nil { - pn := UverseNode() - uverseValue = pn.NewPackage() + switch uverseInit { + case uverseUninitialized: + uverseInit = uverseInitializing + makeUverseNode() + uverseInit = uverseInitialized + case uverseInitializing: + return &PackageValue{} } + return uverseValue } -// Always returns the same instance with possibly differing completeness. +// UverseNode returns the uverse PackageNode. +// If called while initializing the UverseNode itself, it will return an empty +// PackageNode. func UverseNode() *PackageNode { - // Global is singleton. - if uverseNode != nil { - return uverseNode + switch uverseInit { + case uverseUninitialized: + uverseInit = uverseInitializing + makeUverseNode() + uverseInit = uverseInitialized + case uverseInitializing: + return &PackageNode{} } + return uverseNode +} + +func makeUverseNode() { // NOTE: uverse node is hidden, thus the leading dot in pkgPath=".uverse". uverseNode = NewPackageNode("uverse", uversePkgPath, nil) @@ -1017,7 +1046,7 @@ func UverseNode() *PackageNode { m.Exceptions = nil }, ) - return uverseNode + uverseValue = uverseNode.NewPackage() } func copyDataToList(dst []TypedValue, data []byte, et Type) { From 603f6d3a5a4856f4f1b60b4643e253c9e8956c57 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:27:45 -0500 Subject: [PATCH 48/64] chore: relocate tm2/std.MemFile in gnovm/std (#2910) This PR removes "gno.land" from all `tm2/.../*.go` files. --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- gno.land/pkg/gnoclient/client_test.go | 51 +- gno.land/pkg/gnoclient/integration_test.go | 30 +- gno.land/pkg/gnoland/app_test.go | 13 +- gno.land/pkg/gnoweb/gnoweb.go | 4 +- gno.land/pkg/keyscli/run.go | 7 +- gno.land/pkg/sdk/vm/gas_test.go | 7 +- gno.land/pkg/sdk/vm/keeper.go | 3 +- gno.land/pkg/sdk/vm/keeper_test.go | 25 +- gno.land/pkg/sdk/vm/msg_test.go | 15 +- gno.land/pkg/sdk/vm/msgs.go | 21 +- gno.land/pkg/sdk/vm/package.go | 2 + gno.land/pkg/sdk/vm/vm.proto | 10 +- gnovm/cmd/gno/test.go | 6 +- gnovm/gno.proto | 14 +- gnovm/gnovm.proto | 16 + {tm2/pkg/std => gnovm}/memfile.go | 2 +- {tm2/pkg/std => gnovm}/memfile_test.go | 2 +- gnovm/package.go | 15 + gnovm/pkg/gnolang/gnolang.proto | 21 +- gnovm/pkg/gnolang/go2gno.go | 8 +- gnovm/pkg/gnolang/go2gno_test.go | 72 +- gnovm/pkg/gnolang/machine.go | 10 +- gnovm/pkg/gnolang/machine_test.go | 10 +- gnovm/pkg/gnolang/nodes.go | 16 +- gnovm/pkg/gnolang/store.go | 24 +- gnovm/pkg/gnolang/store_test.go | 10 +- gnovm/pkg/gnomod/gnomod.go | 4 +- gnovm/tests/file.go | 5 +- misc/genproto/Makefile | 4 + misc/genproto/genproto.go | 2 + tm2/pkg/amino/tests/pb/tests.pb.go | 5582 ----------------- tm2/pkg/amino/tests/proto3/proto/compat.pb.go | 1044 --- tm2/pkg/libtm/messages/types/messages.pb.go | 543 -- tm2/pkg/std/package.go | 4 - tm2/pkg/std/std.proto | 11 - tm2/pkg/telemetry/config/config.go | 6 +- 36 files changed, 254 insertions(+), 7365 deletions(-) create mode 100644 gnovm/gnovm.proto rename {tm2/pkg/std => gnovm}/memfile.go (99%) rename {tm2/pkg/std => gnovm}/memfile_test.go (99%) create mode 100644 gnovm/package.go delete mode 100644 tm2/pkg/amino/tests/pb/tests.pb.go delete mode 100644 tm2/pkg/amino/tests/proto3/proto/compat.pb.go delete mode 100644 tm2/pkg/libtm/messages/types/messages.pb.go diff --git a/gno.land/pkg/gnoclient/client_test.go b/gno.land/pkg/gnoclient/client_test.go index b7eb21837a7..1f8563d34fe 100644 --- a/gno.land/pkg/gnoclient/client_test.go +++ b/gno.land/pkg/gnoclient/client_test.go @@ -8,6 +8,7 @@ import ( "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" + "github.com/gnolang/gno/gnovm" 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" @@ -17,7 +18,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/std" ) -var testGasFee = ugnot.ValueString(10000) +var testGasFee = ugnot.ValueString(10_000) func TestRender(t *testing.T) { t.Parallel() @@ -652,8 +653,8 @@ func main() { msg := vm.MsgRun{ Caller: caller.GetAddress(), - Package: &std.MemPackage{ - Files: []*std.MemFile{ + Package: &gnovm.MemPackage{ + Files: []*gnovm.MemFile{ { Name: "main.gno", Body: fileBody, @@ -729,8 +730,8 @@ func main() { msg1 := vm.MsgRun{ Caller: caller.GetAddress(), - Package: &std.MemPackage{ - Files: []*std.MemFile{ + Package: &gnovm.MemPackage{ + Files: []*gnovm.MemFile{ { Name: "main1.gno", Body: fileBody, @@ -742,8 +743,8 @@ func main() { msg2 := vm.MsgRun{ Caller: caller.GetAddress(), - Package: &std.MemPackage{ - Files: []*std.MemFile{ + Package: &gnovm.MemPackage{ + Files: []*gnovm.MemFile{ { Name: "main2.gno", Body: fileBody, @@ -794,10 +795,10 @@ func TestRunErrors(t *testing.T) { msgs: []vm.MsgRun{ { Caller: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -841,10 +842,10 @@ func TestRunErrors(t *testing.T) { msgs: []vm.MsgRun{ { Caller: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -872,10 +873,10 @@ func TestRunErrors(t *testing.T) { msgs: []vm.MsgRun{ { Caller: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -903,10 +904,10 @@ func TestRunErrors(t *testing.T) { msgs: []vm.MsgRun{ { Caller: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -943,7 +944,7 @@ func TestRunErrors(t *testing.T) { msgs: []vm.MsgRun{ { Caller: mockAddress, - Package: &std.MemPackage{Name: "", Path: " "}, + Package: &gnovm.MemPackage{Name: "", Path: " "}, Send: nil, }, }, @@ -993,10 +994,10 @@ func TestAddPackageErrors(t *testing.T) { msgs: []vm.MsgAddPackage{ { Creator: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -1040,10 +1041,10 @@ func TestAddPackageErrors(t *testing.T) { msgs: []vm.MsgAddPackage{ { Creator: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -1071,10 +1072,10 @@ func TestAddPackageErrors(t *testing.T) { msgs: []vm.MsgAddPackage{ { Creator: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -1102,10 +1103,10 @@ func TestAddPackageErrors(t *testing.T) { msgs: []vm.MsgAddPackage{ { Creator: mockAddress, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "", Path: "", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "file1.gno", Body: "", @@ -1142,7 +1143,7 @@ func TestAddPackageErrors(t *testing.T) { msgs: []vm.MsgAddPackage{ { Creator: mockAddress, - Package: &std.MemPackage{Name: "", Path: ""}, + Package: &gnovm.MemPackage{Name: "", Path: ""}, Deposit: nil, }, }, diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index 846962766f8..0a06eb4756a 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -5,17 +5,17 @@ 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" "github.com/gnolang/gno/gnovm/pkg/gnoenv" rpcclient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/crypto/keys" "github.com/gnolang/gno/tm2/pkg/log" + "github.com/gnolang/gno/tm2/pkg/sdk/bank" + "github.com/gnolang/gno/tm2/pkg/std" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -316,9 +316,9 @@ func main() { // Make Msg configs msg := vm.MsgRun{ Caller: caller.GetAddress(), - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "main", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "main.gno", Body: fileBody, @@ -393,9 +393,9 @@ func main() { // Make Msg configs msg1 := vm.MsgRun{ Caller: caller.GetAddress(), - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "main", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "main.gno", Body: fileBody1, @@ -406,9 +406,9 @@ func main() { } msg2 := vm.MsgRun{ Caller: caller.GetAddress(), - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "main", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "main.gno", Body: fileBody2, @@ -474,10 +474,10 @@ func Echo(str string) string { // Make Msg config msg := vm.MsgAddPackage{ Creator: caller.GetAddress(), - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "echo", Path: deploymentPath, - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: fileName, Body: body, @@ -564,10 +564,10 @@ func Hello(str string) string { msg1 := vm.MsgAddPackage{ Creator: caller.GetAddress(), - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "echo", Path: deploymentPath1, - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "echo.gno", Body: body1, @@ -579,10 +579,10 @@ func Hello(str string) string { msg2 := vm.MsgAddPackage{ Creator: caller.GetAddress(), - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "hello", Path: deploymentPath2, - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "gno.mod", Body: "module gno.land/p/demo/integration/test/hello", diff --git a/gno.land/pkg/gnoland/app_test.go b/gno.land/pkg/gnoland/app_test.go index 193ff0b0b14..87b624280c6 100644 --- a/gno.land/pkg/gnoland/app_test.go +++ b/gno.land/pkg/gnoland/app_test.go @@ -9,7 +9,8 @@ import ( "time" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" - gnostd "github.com/gnolang/gno/gnovm/stdlibs/std" + "github.com/gnolang/gno/gnovm" + gnostdlibs "github.com/gnolang/gno/gnovm/stdlibs/std" "github.com/gnolang/gno/tm2/pkg/amino" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" bft "github.com/gnolang/gno/tm2/pkg/bft/types" @@ -53,7 +54,7 @@ func TestNewAppWithOptions(t *testing.T) { }, Txs: []std.Tx{ { - Msgs: []std.Msg{vm.NewMsgAddPackage(addr, "gno.land/r/demo", []*std.MemFile{ + Msgs: []std.Msg{vm.NewMsgAddPackage(addr, "gno.land/r/demo", []*gnovm.MemFile{ { Name: "demo.gno", Body: "package demo; func Hello() string { return `hello`; }", @@ -308,7 +309,7 @@ func TestEndBlocker(t *testing.T) { c := newCollector[validatorUpdate](mockEventSwitch, noFilter) // Fire a GnoVM event - mockEventSwitch.FireEvent(gnostd.GnoEvent{}) + mockEventSwitch.FireEvent(gnostdlibs.GnoEvent{}) // Create the EndBlocker eb := EndBlocker(c, mockVMKeeper, &mockEndBlockerApp{}) @@ -351,7 +352,7 @@ func TestEndBlocker(t *testing.T) { c := newCollector[validatorUpdate](mockEventSwitch, noFilter) // Fire a GnoVM event - mockEventSwitch.FireEvent(gnostd.GnoEvent{}) + mockEventSwitch.FireEvent(gnostdlibs.GnoEvent{}) // Create the EndBlocker eb := EndBlocker(c, mockVMKeeper, &mockEndBlockerApp{}) @@ -390,7 +391,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 := gnostdlibs.GnoEvent{ Type: validatorAddedEvent, PkgPath: valRealm, } @@ -399,7 +400,7 @@ func TestEndBlocker(t *testing.T) { if index%2 == 0 { changes[index].Power = 0 - event = gnostd.GnoEvent{ + event = gnostdlibs.GnoEvent{ Type: validatorRemovedEvent, PkgPath: valRealm, } diff --git a/gno.land/pkg/gnoweb/gnoweb.go b/gno.land/pkg/gnoweb/gnoweb.go index c0bc24ce216..ed6271f5afe 100644 --- a/gno.land/pkg/gnoweb/gnoweb.go +++ b/gno.land/pkg/gnoweb/gnoweb.go @@ -18,10 +18,10 @@ import ( "strings" "time" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/amino" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" - "github.com/gnolang/gno/tm2/pkg/std" "github.com/gorilla/mux" "github.com/gotuna/gotuna" @@ -389,7 +389,7 @@ func handlerPackageFile(logger *slog.Logger, app gotuna.App, cfg *Config) http.H return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) pkgpath := "gno.land/p/" + vars["filepath"] - diruri, filename := std.SplitFilepath(pkgpath) + diruri, filename := gnovm.SplitFilepath(pkgpath) if filename == "" && diruri == pkgpath { // redirect to diruri + "/" http.Redirect(w, r, "/p/"+vars["filepath"]+"/", http.StatusFound) diff --git a/gno.land/pkg/keyscli/run.go b/gno.land/pkg/keyscli/run.go index aa0ee298201..b0e05fe5a84 100644 --- a/gno.land/pkg/keyscli/run.go +++ b/gno.land/pkg/keyscli/run.go @@ -8,6 +8,7 @@ import ( "os" "github.com/gnolang/gno/gno.land/pkg/sdk/vm" + "github.com/gnolang/gno/gnovm" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/commands" @@ -73,13 +74,13 @@ func execMakeRun(cfg *MakeRunCfg, args []string, cmdio commands.IO) error { return errors.Wrap(err, "parsing gas fee coin") } - memPkg := &std.MemPackage{} + memPkg := &gnovm.MemPackage{} if sourcePath == "-" { // stdin data, err := io.ReadAll(cmdio.In()) if err != nil { return fmt.Errorf("could not read stdin: %w", err) } - memPkg.Files = []*std.MemFile{ + memPkg.Files = []*gnovm.MemFile{ { Name: "stdin.gno", Body: string(data), @@ -97,7 +98,7 @@ func execMakeRun(cfg *MakeRunCfg, args []string, cmdio commands.IO) error { if err != nil { return fmt.Errorf("could not read %q: %w", sourcePath, err) } - memPkg.Files = []*std.MemFile{ + memPkg.Files = []*gnovm.MemFile{ { Name: info.Name(), Body: string(b), diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index 53809a7f223..a199f12898a 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" + "github.com/gnolang/gno/gnovm" bft "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/sdk" @@ -149,9 +150,9 @@ func setupAddPkg(success bool) (sdk.Context, sdk.Tx, vmHandler) { env.acck.SetAccount(ctx, acc) env.bank.SetCoins(ctx, addr, std.MustParseCoins(ugnot.ValueString(10000000))) // success message - var files []*std.MemFile + var files []*gnovm.MemFile if success { - files = []*std.MemFile{ + files = []*gnovm.MemFile{ { Name: "hello.gno", Body: `package hello @@ -163,7 +164,7 @@ func Echo() string { } } else { // failed message - files = []*std.MemFile{ + files = []*gnovm.MemFile{ { Name: "hello.gno", Body: `package hello diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index ef1705c7ae9..7f5216a4f03 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -14,6 +14,7 @@ import ( "sync" "time" + "github.com/gnolang/gno/gnovm" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/stdlibs" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -832,7 +833,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) - dirpath, filename := std.SplitFilepath(filepath) + dirpath, filename := gnovm.SplitFilepath(filepath) if filename != "" { memFile := store.GetMemFile(dirpath, filename) if memFile == nil { diff --git a/gno.land/pkg/sdk/vm/keeper_test.go b/gno.land/pkg/sdk/vm/keeper_test.go index c6d8e3f5fa0..3aba53d4490 100644 --- a/gno.land/pkg/sdk/vm/keeper_test.go +++ b/gno.land/pkg/sdk/vm/keeper_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/db/memdb" @@ -35,7 +36,7 @@ func TestVMKeeperAddPackage(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ { Name: "test.gno", Body: `package test @@ -80,7 +81,7 @@ func TestVMKeeperOrigSend1(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test @@ -125,7 +126,7 @@ func TestVMKeeperOrigSend2(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test @@ -179,7 +180,7 @@ func TestVMKeeperOrigSend3(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test @@ -223,7 +224,7 @@ func TestVMKeeperRealmSend1(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test @@ -267,7 +268,7 @@ func TestVMKeeperRealmSend2(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test @@ -312,7 +313,7 @@ func TestVMKeeperParams(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {"init.gno", ` package test @@ -365,7 +366,7 @@ func TestVMKeeperOrigCallerInit(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test @@ -416,7 +417,7 @@ func TestVMKeeperRunSimple(t *testing.T) { acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "script.gno", Body: ` package main @@ -455,7 +456,7 @@ func testVMKeeperRunImportStdlibs(t *testing.T, env testEnv) { acc := env.acck.NewAccountWithAddress(ctx, addr) env.acck.SetAccount(ctx, acc) - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "script.gno", Body: ` package main @@ -488,7 +489,7 @@ func TestNumberOfArgsError(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ { Name: "test.gno", Body: `package test @@ -527,7 +528,7 @@ func TestVMKeeperReinitialize(t *testing.T) { assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins(coinsString))) // Create test package. - files := []*std.MemFile{ + files := []*gnovm.MemFile{ {Name: "init.gno", Body: ` package test diff --git a/gno.land/pkg/sdk/vm/msg_test.go b/gno.land/pkg/sdk/vm/msg_test.go index eaaaa0f0ab2..684dc21e9f2 100644 --- a/gno.land/pkg/sdk/vm/msg_test.go +++ b/gno.land/pkg/sdk/vm/msg_test.go @@ -3,6 +3,7 @@ package vm import ( "testing" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/std" "github.com/stretchr/testify/assert" @@ -14,7 +15,7 @@ func TestMsgAddPackage_ValidateBasic(t *testing.T) { creator := crypto.AddressFromPreimage([]byte("addr1")) pkgName := "test" pkgPath := "gno.land/r/namespace/test" - files := []*std.MemFile{ + files := []*gnovm.MemFile{ { Name: "test.gno", Body: `package test @@ -40,7 +41,7 @@ func TestMsgAddPackage_ValidateBasic(t *testing.T) { name: "missing creator address", msg: MsgAddPackage{ Creator: crypto.Address{}, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: pkgName, Path: pkgPath, Files: files, @@ -56,7 +57,7 @@ func TestMsgAddPackage_ValidateBasic(t *testing.T) { name: "missing package path", msg: MsgAddPackage{ Creator: creator, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: pkgName, Path: "", Files: files, @@ -72,7 +73,7 @@ func TestMsgAddPackage_ValidateBasic(t *testing.T) { name: "invalid deposit coins", msg: MsgAddPackage{ Creator: creator, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: pkgName, Path: pkgPath, Files: files, @@ -199,7 +200,7 @@ func TestMsgRun_ValidateBasic(t *testing.T) { caller := crypto.AddressFromPreimage([]byte("addr1")) pkgName := "main" pkgPath := "gno.land/r/" + caller.String() + "/run" - pkgFiles := []*std.MemFile{ + pkgFiles := []*gnovm.MemFile{ { Name: "main.gno", Body: `package main @@ -226,7 +227,7 @@ func TestMsgRun_ValidateBasic(t *testing.T) { name: "invalid caller address", msg: MsgRun{ Caller: crypto.Address{}, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: pkgName, Path: pkgPath, Files: pkgFiles, @@ -242,7 +243,7 @@ func TestMsgRun_ValidateBasic(t *testing.T) { name: "invalid package path", msg: MsgRun{ Caller: caller, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: pkgName, Path: "gno.land/r/namespace/test", // this is not a valid run path Files: pkgFiles, diff --git a/gno.land/pkg/sdk/vm/msgs.go b/gno.land/pkg/sdk/vm/msgs.go index d650c23f382..d5b82067a98 100644 --- a/gno.land/pkg/sdk/vm/msgs.go +++ b/gno.land/pkg/sdk/vm/msgs.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/gnolang/gno/gnovm" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -16,15 +17,15 @@ import ( // MsgAddPackage - create and initialize new package type MsgAddPackage struct { - Creator crypto.Address `json:"creator" yaml:"creator"` - Package *std.MemPackage `json:"package" yaml:"package"` - Deposit std.Coins `json:"deposit" yaml:"deposit"` + Creator crypto.Address `json:"creator" yaml:"creator"` + Package *gnovm.MemPackage `json:"package" yaml:"package"` + Deposit std.Coins `json:"deposit" yaml:"deposit"` } var _ std.Msg = MsgAddPackage{} // NewMsgAddPackage - upload a package with files. -func NewMsgAddPackage(creator crypto.Address, pkgPath string, files []*std.MemFile) MsgAddPackage { +func NewMsgAddPackage(creator crypto.Address, pkgPath string, files []*gnovm.MemFile) MsgAddPackage { var pkgName string for _, file := range files { if strings.HasSuffix(file.Name, ".gno") { @@ -34,7 +35,7 @@ func NewMsgAddPackage(creator crypto.Address, pkgPath string, files []*std.MemFi } return MsgAddPackage{ Creator: creator, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: pkgName, Path: pkgPath, Files: files, @@ -145,14 +146,14 @@ func (msg MsgCall) GetReceived() std.Coins { // MsgRun - executes arbitrary Gno code. type MsgRun struct { - Caller crypto.Address `json:"caller" yaml:"caller"` - Send std.Coins `json:"send" yaml:"send"` - Package *std.MemPackage `json:"package" yaml:"package"` + Caller crypto.Address `json:"caller" yaml:"caller"` + Send std.Coins `json:"send" yaml:"send"` + Package *gnovm.MemPackage `json:"package" yaml:"package"` } var _ std.Msg = MsgRun{} -func NewMsgRun(caller crypto.Address, send std.Coins, files []*std.MemFile) MsgRun { +func NewMsgRun(caller crypto.Address, send std.Coins, files []*gnovm.MemFile) MsgRun { for _, file := range files { if strings.HasSuffix(file.Name, ".gno") { pkgName := string(gno.PackageNameFromFileBody(file.Name, file.Body)) @@ -164,7 +165,7 @@ func NewMsgRun(caller crypto.Address, send std.Coins, files []*std.MemFile) MsgR return MsgRun{ Caller: caller, Send: send, - Package: &std.MemPackage{ + Package: &gnovm.MemPackage{ Name: "main", Path: "", // auto set by the handler Files: files, diff --git a/gno.land/pkg/sdk/vm/package.go b/gno.land/pkg/sdk/vm/package.go index 30dd116d4e3..0359061ccea 100644 --- a/gno.land/pkg/sdk/vm/package.go +++ b/gno.land/pkg/sdk/vm/package.go @@ -1,6 +1,7 @@ package vm import ( + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/std" ) @@ -11,6 +12,7 @@ var Package = amino.RegisterPackage(amino.NewPackage( amino.GetCallersDirname(), ).WithDependencies( std.Package, + gnovm.Package, ).WithTypes( MsgCall{}, "m_call", MsgRun{}, "m_run", diff --git a/gno.land/pkg/sdk/vm/vm.proto b/gno.land/pkg/sdk/vm/vm.proto index e02226e1ae4..efaf025e431 100644 --- a/gno.land/pkg/sdk/vm/vm.proto +++ b/gno.land/pkg/sdk/vm/vm.proto @@ -5,6 +5,7 @@ option go_package = "github.com/gnolang/gno/gno.land/pkg/sdk/vm/pb"; // imports import "github.com/gnolang/gno/tm2/pkg/std/std.proto"; +import "github.com/gnolang/gno/gnovm/gnovm.proto"; // messages message m_call { @@ -18,12 +19,12 @@ message m_call { message m_run { string caller = 1; string send = 2; - std.MemPackage package = 3; + gnovm.MemPackage package = 3; } message m_addpkg { string creator = 1; - std.MemPackage package = 2; + gnovm.MemPackage package = 2; string deposit = 3; } @@ -40,5 +41,8 @@ message InvalidExprError { } message TypeCheckError { - repeated string errors = 1 [json_name = "Errors"]; + repeated string errors = 1; +} + +message UnauthorizedUserError { } \ No newline at end of file diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index e23f9fa2750..c6feebfd2b5 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -17,6 +17,7 @@ import ( "go.uber.org/multierr" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" @@ -25,7 +26,6 @@ import ( "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/random" - "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/testutils" ) @@ -324,7 +324,7 @@ func gnoTestPkg( m := tests.TestMachine(testStore, stdout, testPkgName) - memFiles := make([]*std.MemFile, 0, len(ifiles.FileNames())+1) + memFiles := make([]*gnovm.MemFile, 0, len(ifiles.FileNames())+1) for _, f := range memPkg.Files { for _, ifileName := range ifiles.FileNames() { if f.Name == "gno.mod" || f.Name == ifileName { @@ -599,7 +599,7 @@ func loadTestFuncs(pkgName string, t *testFuncs, tfiles *gno.FileSet) *testFuncs // parseMemPackageTests is copied from gno.ParseMemPackageTests // for except to _filetest.gno -func parseMemPackageTests(memPkg *std.MemPackage) (tset, itset *gno.FileSet) { +func parseMemPackageTests(memPkg *gnovm.MemPackage) (tset, itset *gno.FileSet) { tset = &gno.FileSet{} itset = &gno.FileSet{} var errs error diff --git a/gnovm/gno.proto b/gnovm/gno.proto index 5f53c363b73..8a15ca96e14 100644 --- a/gnovm/gno.proto +++ b/gnovm/gno.proto @@ -1,7 +1,7 @@ syntax = "proto3"; package gno; -option go_package = "github.com/gnolang/gno/pb"; +option go_package = "github.com/gnolang/gno/gnovm/pb"; // imports import "google/protobuf/any.proto"; @@ -601,3 +601,15 @@ message tupleType { message RefType { string ID = 1; } + +// messages +message MemFile { + string name = 1; + string body = 2; +} + +message MemPackage { + string name = 1; + string path = 2; + repeated MemFile files = 3; +} diff --git a/gnovm/gnovm.proto b/gnovm/gnovm.proto new file mode 100644 index 00000000000..c9f0b23ae80 --- /dev/null +++ b/gnovm/gnovm.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package gnovm; + +option go_package = "github.com/gnolang/gno/gnovm/pb"; + +// messages +message MemFile { + string name = 1; + string body = 2; +} + +message MemPackage { + string name = 1; + string path = 2; + repeated MemFile files = 3; +} \ No newline at end of file diff --git a/tm2/pkg/std/memfile.go b/gnovm/memfile.go similarity index 99% rename from tm2/pkg/std/memfile.go rename to gnovm/memfile.go index 01bc18c1487..a37bba6ef3d 100644 --- a/tm2/pkg/std/memfile.go +++ b/gnovm/memfile.go @@ -1,4 +1,4 @@ -package std +package gnovm import ( "fmt" diff --git a/tm2/pkg/std/memfile_test.go b/gnovm/memfile_test.go similarity index 99% rename from tm2/pkg/std/memfile_test.go rename to gnovm/memfile_test.go index 3e1fb49e131..c93c251b0e7 100644 --- a/tm2/pkg/std/memfile_test.go +++ b/gnovm/memfile_test.go @@ -1,4 +1,4 @@ -package std +package gnovm import ( "testing" diff --git a/gnovm/package.go b/gnovm/package.go new file mode 100644 index 00000000000..d6332b05709 --- /dev/null +++ b/gnovm/package.go @@ -0,0 +1,15 @@ +package gnovm + +import ( + "github.com/gnolang/gno/tm2/pkg/amino" +) + +var Package = amino.RegisterPackage(amino.NewPackage( + "github.com/gnolang/gno/gnovm", + "gnovm", + amino.GetCallersDirname(), +).WithDependencies().WithTypes( + // MemFile/MemPackage + MemFile{}, "MemFile", + MemPackage{}, "MemPackage", +)) diff --git a/gnovm/pkg/gnolang/gnolang.proto b/gnovm/pkg/gnolang/gnolang.proto index eee9a0375e6..27c26534a5f 100644 --- a/gnovm/pkg/gnolang/gnolang.proto +++ b/gnovm/pkg/gnolang/gnolang.proto @@ -56,10 +56,11 @@ message FuncValue { google.protobuf.Any source = 3 [json_name = "Source"]; string name = 4 [json_name = "Name"]; google.protobuf.Any closure = 5 [json_name = "Closure"]; - string file_name = 6 [json_name = "FileName"]; - string pkg_path = 7 [json_name = "PkgPath"]; - string native_pkg = 8 [json_name = "NativePkg"]; - string native_name = 9 [json_name = "NativeName"]; + repeated TypedValue captures = 6 [json_name = "Captures"]; + string file_name = 7 [json_name = "FileName"]; + string pkg_path = 8 [json_name = "PkgPath"]; + string native_pkg = 9 [json_name = "NativePkg"]; + string native_name = 10 [json_name = "NativeName"]; } message MapValue { @@ -110,6 +111,11 @@ message RefValue { string hash = 4 [json_name = "Hash"]; } +message HeapItemValue { + ObjectInfo object_info = 1 [json_name = "ObjectInfo"]; + TypedValue value = 2 [json_name = "Value"]; +} + message ObjectID { string value = 1; } @@ -147,13 +153,15 @@ message Location { message Attributes { sint64 line = 1 [json_name = "Line"]; - string label = 2 [json_name = "Label"]; + sint64 column = 2 [json_name = "Column"]; + string label = 3 [json_name = "Label"]; } message NameExpr { Attributes attributes = 1 [json_name = "Attributes"]; ValuePath path = 2 [json_name = "Path"]; string name = 3 [json_name = "Name"]; + sint64 type = 4 [json_name = "Type"]; } message BasicLitExpr { @@ -239,6 +247,7 @@ message FuncLitExpr { StaticBlock static_block = 2 [json_name = "StaticBlock"]; FuncTypeExpr type = 3 [json_name = "Type"]; repeated google.protobuf.Any body = 4 [json_name = "Body"]; + repeated NameExpr heap_captures = 5 [json_name = "HeapCaptures"]; } message ConstExpr { @@ -602,4 +611,4 @@ message tupleType { message RefType { string id = 1 [json_name = "ID"]; -} +} \ No newline at end of file diff --git a/gnovm/pkg/gnolang/go2gno.go b/gnovm/pkg/gnolang/go2gno.go index 6bde6fb5271..99e051f7913 100644 --- a/gnovm/pkg/gnolang/go2gno.go +++ b/gnovm/pkg/gnolang/go2gno.go @@ -44,8 +44,8 @@ import ( "strings" "github.com/davecgh/go-spew/spew" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/errors" - "github.com/gnolang/gno/tm2/pkg/std" "go.uber.org/multierr" ) @@ -486,7 +486,7 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { // MemPackageGetter implements the GetMemPackage() method. It is a subset of // [Store], separated for ease of testing. type MemPackageGetter interface { - GetMemPackage(path string) *std.MemPackage + GetMemPackage(path string) *gnovm.MemPackage } // TypeCheckMemPackage performs type validation and checking on the given @@ -496,7 +496,7 @@ type MemPackageGetter interface { // // If format is true, the code will be automatically updated with the // formatted source code. -func TypeCheckMemPackage(mempkg *std.MemPackage, getter MemPackageGetter, format bool) error { +func TypeCheckMemPackage(mempkg *gnovm.MemPackage, getter MemPackageGetter, format bool) error { var errs error imp := &gnoImporter{ getter: getter, @@ -556,7 +556,7 @@ func (g *gnoImporter) ImportFrom(path, _ string, _ types.ImportMode) (*types.Pac return result, err } -func (g *gnoImporter) parseCheckMemPackage(mpkg *std.MemPackage, fmt bool) (*types.Package, error) { +func (g *gnoImporter) parseCheckMemPackage(mpkg *gnovm.MemPackage, fmt bool) (*types.Package, error) { fset := token.NewFileSet() files := make([]*ast.File, 0, len(mpkg.Files)) var errs error diff --git a/gnovm/pkg/gnolang/go2gno_test.go b/gnovm/pkg/gnolang/go2gno_test.go index d85c142ca52..8aba5d7f293 100644 --- a/gnovm/pkg/gnolang/go2gno_test.go +++ b/gnovm/pkg/gnolang/go2gno_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/gnolang/gno/tm2/pkg/std" + "github.com/gnolang/gno/gnovm" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/multierr" @@ -29,9 +29,9 @@ func main(){ fmt.Printf("AST.String():\n%s\n", n.String()) } -type mockPackageGetter []*std.MemPackage +type mockPackageGetter []*gnovm.MemPackage -func (mi mockPackageGetter) GetMemPackage(path string) *std.MemPackage { +func (mi mockPackageGetter) GetMemPackage(path string) *gnovm.MemPackage { for _, pkg := range mi { if pkg.Path == path { return pkg @@ -45,7 +45,7 @@ type mockPackageGetterCounts struct { counts map[string]int } -func (mpg mockPackageGetterCounts) GetMemPackage(path string) *std.MemPackage { +func (mpg mockPackageGetterCounts) GetMemPackage(path string) *gnovm.MemPackage { mpg.counts[path]++ return mpg.mockPackageGetter.GetMemPackage(path) } @@ -77,17 +77,17 @@ func TestTypeCheckMemPackage(t *testing.T) { type testCase struct { name string - pkg *std.MemPackage + pkg *gnovm.MemPackage getter MemPackageGetter check func(*testing.T, error) } tt := []testCase{ { "Simple", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -103,10 +103,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "WrongReturn", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -122,10 +122,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "ParseError", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -139,10 +139,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "MultiError", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "main", Path: "gno.land/p/demo/main", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -159,10 +159,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "TestsIgnored", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -181,10 +181,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "ImportFailed", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -199,10 +199,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "ImportSucceeded", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -213,12 +213,12 @@ func TestTypeCheckMemPackage(t *testing.T) { }, }, mockPackageGetter{ - &std.MemPackage{ + &gnovm.MemPackage{ Name: "std", Path: "std", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { - Name: "std.gno", + Name: "gnovm.gno", Body: ` package std type Address string`, @@ -230,10 +230,10 @@ func TestTypeCheckMemPackage(t *testing.T) { }, { "ImportBadIdent", - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -244,12 +244,12 @@ func TestTypeCheckMemPackage(t *testing.T) { }, }, mockPackageGetter{ - &std.MemPackage{ + &gnovm.MemPackage{ Name: "a_completely_different_identifier", Path: "std", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { - Name: "std.gno", + Name: "gnovm.gno", Body: ` package a_completely_different_identifier type Address string`, @@ -263,10 +263,10 @@ func TestTypeCheckMemPackage(t *testing.T) { cacheMpg := mockPackageGetterCounts{ mockPackageGetter{ - &std.MemPackage{ + &gnovm.MemPackage{ Name: "bye", Path: "bye", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "bye.gno", Body: ` @@ -276,12 +276,12 @@ func TestTypeCheckMemPackage(t *testing.T) { }, }, }, - &std.MemPackage{ + &gnovm.MemPackage{ Name: "std", Path: "std", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { - Name: "std.gno", + Name: "gnovm.gno", Body: ` package std type Address string`, @@ -295,10 +295,10 @@ func TestTypeCheckMemPackage(t *testing.T) { tt = append(tt, testCase{ "ImportWithCache", // This test will make use of the importer's internal cache for package `std`. - &std.MemPackage{ + &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: ` @@ -347,10 +347,10 @@ func TestTypeCheckMemPackage_format(t *testing.T) { ` - pkg := &std.MemPackage{ + pkg := &gnovm.MemPackage{ Name: "hello", Path: "gno.land/p/demo/hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "hello.gno", Body: input, diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 1e594de945b..09be71682a5 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -16,8 +16,8 @@ import ( "github.com/gnolang/overflow" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/errors" - "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store" ) @@ -265,7 +265,7 @@ func (m *Machine) PreprocessAllFilesAndSaveBlockNodes() { // Parses files, sets the package if doesn't exist, runs files, saves mempkg // and corresponding package node, package value, and types to store. Save // is set to false for tests where package values may be native. -func (m *Machine) RunMemPackage(memPkg *std.MemPackage, save bool) (*PackageNode, *PackageValue) { +func (m *Machine) RunMemPackage(memPkg *gnovm.MemPackage, save bool) (*PackageNode, *PackageValue) { return m.runMemPackage(memPkg, save, false) } @@ -273,11 +273,11 @@ func (m *Machine) RunMemPackage(memPkg *std.MemPackage, save bool) (*PackageNode // declarations are filtered removing duplicate declarations. // To control which declaration overrides which, use [ReadMemPackageFromList], // putting the overrides at the top of the list. -func (m *Machine) RunMemPackageWithOverrides(memPkg *std.MemPackage, save bool) (*PackageNode, *PackageValue) { +func (m *Machine) RunMemPackageWithOverrides(memPkg *gnovm.MemPackage, save bool) (*PackageNode, *PackageValue) { return m.runMemPackage(memPkg, save, true) } -func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (*PackageNode, *PackageValue) { +func (m *Machine) runMemPackage(memPkg *gnovm.MemPackage, save, overrides bool) (*PackageNode, *PackageValue) { // parse files. files := ParseMemPackage(memPkg) if !overrides { @@ -406,7 +406,7 @@ func destar(x Expr) Expr { // The resulting package value and node become injected with TestMethods and // other declarations, so it is expected that non-test code will not be run // afterwards from the same store. -func (m *Machine) TestMemPackage(t *testing.T, memPkg *std.MemPackage) { +func (m *Machine) TestMemPackage(t *testing.T, memPkg *gnovm.MemPackage) { defer m.injectLocOnPanic() DisableDebug() fmt.Println("DEBUG DISABLED (FOR TEST DEPENDENCIES INIT)") diff --git a/gnovm/pkg/gnolang/machine_test.go b/gnovm/pkg/gnolang/machine_test.go index 8e27b127fbb..c3b2118f099 100644 --- a/gnovm/pkg/gnolang/machine_test.go +++ b/gnovm/pkg/gnolang/machine_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/db/memdb" - "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/store/dbadapter" "github.com/gnolang/gno/tm2/pkg/store/iavl" stypes "github.com/gnolang/gno/tm2/pkg/store/types" @@ -27,10 +27,10 @@ func TestRunMemPackageWithOverrides_revertToOld(t *testing.T) { iavlStore := iavl.StoreConstructor(db, stypes.StoreOptions{}) store := NewStore(nil, baseStore, iavlStore) m := NewMachine("std", store) - m.RunMemPackageWithOverrides(&std.MemPackage{ + m.RunMemPackageWithOverrides(&gnovm.MemPackage{ Name: "std", Path: "std", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ {Name: "a.gno", Body: `package std; func Redecl(x int) string { return "1" }`}, }, }, true) @@ -38,10 +38,10 @@ func TestRunMemPackageWithOverrides_revertToOld(t *testing.T) { defer func() { p = fmt.Sprint(recover()) }() - m.RunMemPackageWithOverrides(&std.MemPackage{ + m.RunMemPackageWithOverrides(&gnovm.MemPackage{ Name: "std", Path: "std", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ {Name: "b.gno", Body: `package std; func Redecl(x int) string { var y string; _, _ = y; return "2" }`}, }, }, true) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 9e7cea8fb7f..c282b619fdc 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -12,8 +12,8 @@ import ( "strconv" "strings" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/tm2/pkg/errors" - "github.com/gnolang/gno/tm2/pkg/std" "go.uber.org/multierr" ) @@ -1152,7 +1152,7 @@ func PackageNameFromFileBody(name, body string) Name { // // NOTE: panics if package name is invalid (characters must be alphanumeric or _, // lowercase, and must start with a letter). -func ReadMemPackage(dir string, pkgPath string) *std.MemPackage { +func ReadMemPackage(dir string, pkgPath string) *gnovm.MemPackage { files, err := os.ReadDir(dir) if err != nil { panic(err) @@ -1186,14 +1186,14 @@ func ReadMemPackage(dir string, pkgPath string) *std.MemPackage { return ReadMemPackageFromList(list, pkgPath) } -// ReadMemPackageFromList creates a new [std.MemPackage] with the specified pkgPath, +// ReadMemPackageFromList creates a new [gnovm.MemPackage] with the specified pkgPath, // containing the contents of all the files provided in the list slice. // No parsing or validation is done on the filenames. // // NOTE: panics if package name is invalid (characters must be alphanumeric or _, // lowercase, and must start with a letter). -func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { - memPkg := &std.MemPackage{Path: pkgPath} +func ReadMemPackageFromList(list []string, pkgPath string) *gnovm.MemPackage { + memPkg := &gnovm.MemPackage{Path: pkgPath} var pkgName Name for _, fpath := range list { fname := filepath.Base(fpath) @@ -1209,7 +1209,7 @@ func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { } } memPkg.Files = append(memPkg.Files, - &std.MemFile{ + &gnovm.MemFile{ Name: fname, Body: string(bz), }) @@ -1229,7 +1229,7 @@ func ReadMemPackageFromList(list []string, pkgPath string) *std.MemPackage { // // If one of the files has a different package name than memPkg.Name, // or [ParseFile] returns an error, ParseMemPackage panics. -func ParseMemPackage(memPkg *std.MemPackage) (fset *FileSet) { +func ParseMemPackage(memPkg *gnovm.MemPackage) (fset *FileSet) { fset = &FileSet{} var errs error for _, mfile := range memPkg.Files { @@ -1256,7 +1256,7 @@ func ParseMemPackage(memPkg *std.MemPackage) (fset *FileSet) { return fset } -func ParseMemPackageTests(memPkg *std.MemPackage) (tset, itset *FileSet) { +func ParseMemPackageTests(memPkg *gnovm.MemPackage) (tset, itset *FileSet) { tset = &FileSet{} itset = &FileSet{} for _, mfile := range memPkg.Files { diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 9913c434282..dfb1e9f114c 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -7,10 +7,10 @@ import ( "strconv" "strings" + "github.com/gnolang/gno/gnovm" "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/utils" stringz "github.com/gnolang/gno/tm2/pkg/strings" @@ -58,10 +58,10 @@ type Store interface { // Upon restart, all packages will be re-preprocessed; This // loads BlockNodes and Types onto the store for persistence // version 1. - AddMemPackage(memPkg *std.MemPackage) - GetMemPackage(path string) *std.MemPackage - GetMemFile(path string, name string) *std.MemFile - IterMemPackage() <-chan *std.MemPackage + AddMemPackage(memPkg *gnovm.MemPackage) + GetMemPackage(path string) *gnovm.MemPackage + GetMemFile(path string, name string) *gnovm.MemFile + IterMemPackage() <-chan *gnovm.MemPackage ClearObjectCache() // run before processing a message SetNativeStore(NativeStore) // for "new" natives XXX GetNative(pkgPath string, name Name) func(m *Machine) // for "new" natives XXX @@ -611,7 +611,7 @@ func (ds *defaultStore) incGetPackageIndexCounter() uint64 { } } -func (ds *defaultStore) AddMemPackage(memPkg *std.MemPackage) { +func (ds *defaultStore) AddMemPackage(memPkg *gnovm.MemPackage) { memPkg.Validate() // NOTE: duplicate validation. ctr := ds.incGetPackageIndexCounter() idxkey := []byte(backendPackageIndexKey(ctr)) @@ -623,11 +623,11 @@ func (ds *defaultStore) AddMemPackage(memPkg *std.MemPackage) { // GetMemPackage retrieves the MemPackage at the given path. // It returns nil if the package could not be found. -func (ds *defaultStore) GetMemPackage(path string) *std.MemPackage { +func (ds *defaultStore) GetMemPackage(path string) *gnovm.MemPackage { return ds.getMemPackage(path, false) } -func (ds *defaultStore) getMemPackage(path string, isRetry bool) *std.MemPackage { +func (ds *defaultStore) getMemPackage(path string, isRetry bool) *gnovm.MemPackage { pathkey := []byte(backendPackagePathKey(path)) bz := ds.iavlStore.Get(pathkey) if bz == nil { @@ -644,7 +644,7 @@ func (ds *defaultStore) getMemPackage(path string, isRetry bool) *std.MemPackage return nil } - var memPkg *std.MemPackage + var memPkg *gnovm.MemPackage amino.MustUnmarshal(bz, &memPkg) return memPkg } @@ -652,7 +652,7 @@ func (ds *defaultStore) getMemPackage(path string, isRetry bool) *std.MemPackage // GetMemFile retrieves the MemFile with the given name, contained in the // MemPackage at the given path. It returns nil if the file or the package // do not exist. -func (ds *defaultStore) GetMemFile(path string, name string) *std.MemFile { +func (ds *defaultStore) GetMemFile(path string, name string) *gnovm.MemFile { memPkg := ds.GetMemPackage(path) if memPkg == nil { return nil @@ -661,7 +661,7 @@ func (ds *defaultStore) GetMemFile(path string, name string) *std.MemFile { return memFile } -func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage { +func (ds *defaultStore) IterMemPackage() <-chan *gnovm.MemPackage { ctrkey := []byte(backendPackageIndexCtrKey()) ctrbz := ds.baseStore.Get(ctrkey) if ctrbz == nil { @@ -671,7 +671,7 @@ func (ds *defaultStore) IterMemPackage() <-chan *std.MemPackage { if err != nil { panic(err) } - ch := make(chan *std.MemPackage, 0) + ch := make(chan *gnovm.MemPackage, 0) go func() { for i := uint64(1); i <= uint64(ctr); i++ { idxkey := []byte(backendPackageIndexKey(i)) diff --git a/gnovm/pkg/gnolang/store_test.go b/gnovm/pkg/gnolang/store_test.go index 17f55993705..40f84b65375 100644 --- a/gnovm/pkg/gnolang/store_test.go +++ b/gnovm/pkg/gnolang/store_test.go @@ -4,8 +4,8 @@ import ( "io" "testing" + "github.com/gnolang/gno/gnovm" "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" @@ -23,10 +23,10 @@ func TestTransactionStore(t *testing.T) { Store: txSt, Output: io.Discard, }) - _, pv := m.RunMemPackage(&std.MemPackage{ + _, pv := m.RunMemPackage(&gnovm.MemPackage{ Name: "hello", Path: "hello", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ {Name: "hello.gno", Body: "package hello; func main() { println(A(11)); }; type A int"}, }, }, true) @@ -75,10 +75,10 @@ func TestCopyFromCachedStore(t *testing.T) { Name: "Reader", Base: BoolType, }) - cachedStore.AddMemPackage(&std.MemPackage{ + cachedStore.AddMemPackage(&gnovm.MemPackage{ Name: "math", Path: "math", - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ {Name: "math.gno", Body: "package math"}, }, }) diff --git a/gnovm/pkg/gnomod/gnomod.go b/gnovm/pkg/gnomod/gnomod.go index 0effa532107..553bb32f4b5 100644 --- a/gnovm/pkg/gnomod/gnomod.go +++ b/gnovm/pkg/gnomod/gnomod.go @@ -9,10 +9,10 @@ import ( "path/filepath" "strings" + "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/gnovm/pkg/gnoenv" "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/transpiler" - "github.com/gnolang/gno/tm2/pkg/std" "golang.org/x/mod/modfile" "golang.org/x/mod/module" ) @@ -43,7 +43,7 @@ func writePackage(remote, basePath, pkgPath string) (requirements []string, err return nil, fmt.Errorf("querychain (%s): %w", pkgPath, err) } - dirPath, fileName := std.SplitFilepath(pkgPath) + dirPath, fileName := gnovm.SplitFilepath(pkgPath) if fileName == "" { // Is Dir // Create Dir if not exists diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index 5449adc01d2..9df982d4fd8 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -15,6 +15,7 @@ import ( "strings" "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" + "github.com/gnolang/gno/gnovm" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/stdlibs" teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" @@ -200,10 +201,10 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { store.SetStrictGo2GnoMapping(true) // in gno.land, natives must be registered. gno.DisableDebug() // until main call. // save package using realm crawl procedure. - memPkg := &std.MemPackage{ + memPkg := &gnovm.MemPackage{ Name: string(pkgName), Path: pkgPath, - Files: []*std.MemFile{ + Files: []*gnovm.MemFile{ { Name: "main.gno", // dontcare Body: string(bz), diff --git a/misc/genproto/Makefile b/misc/genproto/Makefile index 1033a1b2b24..8c4bfc3118b 100644 --- a/misc/genproto/Makefile +++ b/misc/genproto/Makefile @@ -9,3 +9,7 @@ all: --go_opt=Mproto/compat.proto=github.com/gnolang/gno/tm2/pkg/amino/tests/proto3 \ --go-grpc_opt=Mproto/compat.proto=github.com/gnolang/gno/tm2/pkg/amino/tests/proto3 \ --go-grpc_out=. --go-grpc_opt=paths=source_relative proto/compat.proto + +deps: + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest diff --git a/misc/genproto/genproto.go b/misc/genproto/genproto.go index b9b97efbe37..c1dfd75ce40 100644 --- a/misc/genproto/genproto.go +++ b/misc/genproto/genproto.go @@ -11,6 +11,7 @@ import ( // TODO: move these out. "github.com/gnolang/gno/gno.land/pkg/sdk/vm" + "github.com/gnolang/gno/gnovm" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" "github.com/gnolang/gno/tm2/pkg/bft/blockchain" @@ -54,6 +55,7 @@ func execGen(_ context.Context, _ []string) error { hd.Package, multisig.Package, std.Package, + gnovm.Package, sdk.Package, bank.Package, vm.Package, diff --git a/tm2/pkg/amino/tests/pb/tests.pb.go b/tm2/pkg/amino/tests/pb/tests.pb.go deleted file mode 100644 index 6776f5ecb57..00000000000 --- a/tm2/pkg/amino/tests/pb/tests.pb.go +++ /dev/null @@ -1,5582 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 -// source: tests.proto - -package pb - -import ( - reflect "reflect" - sync "sync" - - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - anypb "google.golang.org/protobuf/types/known/anypb" - durationpb "google.golang.org/protobuf/types/known/durationpb" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// messages -type EmptyStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *EmptyStruct) Reset() { - *x = EmptyStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmptyStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmptyStruct) ProtoMessage() {} - -func (x *EmptyStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmptyStruct.ProtoReflect.Descriptor instead. -func (*EmptyStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{0} -} - -type PrimitivesStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8 int32 `protobuf:"zigzag32,1,opt,name=int8,json=Int8,proto3" json:"int8,omitempty"` - Int16 int32 `protobuf:"zigzag32,2,opt,name=int16,json=Int16,proto3" json:"int16,omitempty"` - Int32 int32 `protobuf:"zigzag32,3,opt,name=int32,json=Int32,proto3" json:"int32,omitempty"` - Int32Fixed int32 `protobuf:"fixed32,4,opt,name=int32_fixed,json=Int32Fixed,proto3" json:"int32_fixed,omitempty"` - Int64 int64 `protobuf:"zigzag64,5,opt,name=int64,json=Int64,proto3" json:"int64,omitempty"` - Int64Fixed int64 `protobuf:"fixed64,6,opt,name=int64_fixed,json=Int64Fixed,proto3" json:"int64_fixed,omitempty"` - Int int64 `protobuf:"zigzag64,7,opt,name=int,json=Int,proto3" json:"int,omitempty"` - Byte uint32 `protobuf:"varint,8,opt,name=byte,json=Byte,proto3" json:"byte,omitempty"` - Uint8 uint32 `protobuf:"varint,9,opt,name=uint8,json=Uint8,proto3" json:"uint8,omitempty"` - Uint16 uint32 `protobuf:"varint,10,opt,name=uint16,json=Uint16,proto3" json:"uint16,omitempty"` - Uint32 uint32 `protobuf:"varint,11,opt,name=uint32,json=Uint32,proto3" json:"uint32,omitempty"` - Uint32Fixed uint32 `protobuf:"fixed32,12,opt,name=uint32_fixed,json=Uint32Fixed,proto3" json:"uint32_fixed,omitempty"` - Uint64 uint64 `protobuf:"varint,13,opt,name=uint64,json=Uint64,proto3" json:"uint64,omitempty"` - Uint64Fixed uint64 `protobuf:"fixed64,14,opt,name=uint64_fixed,json=Uint64Fixed,proto3" json:"uint64_fixed,omitempty"` - Uint uint64 `protobuf:"varint,15,opt,name=uint,json=Uint,proto3" json:"uint,omitempty"` - Str string `protobuf:"bytes,16,opt,name=str,json=Str,proto3" json:"str,omitempty"` - Bytes []byte `protobuf:"bytes,17,opt,name=bytes,json=Bytes,proto3" json:"bytes,omitempty"` - Time *timestamppb.Timestamp `protobuf:"bytes,18,opt,name=time,json=Time,proto3" json:"time,omitempty"` - Duration *durationpb.Duration `protobuf:"bytes,19,opt,name=duration,json=Duration,proto3" json:"duration,omitempty"` - Empty *EmptyStruct `protobuf:"bytes,20,opt,name=empty,json=Empty,proto3" json:"empty,omitempty"` -} - -func (x *PrimitivesStruct) Reset() { - *x = PrimitivesStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrimitivesStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrimitivesStruct) ProtoMessage() {} - -func (x *PrimitivesStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrimitivesStruct.ProtoReflect.Descriptor instead. -func (*PrimitivesStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{1} -} - -func (x *PrimitivesStruct) GetInt8() int32 { - if x != nil { - return x.Int8 - } - return 0 -} - -func (x *PrimitivesStruct) GetInt16() int32 { - if x != nil { - return x.Int16 - } - return 0 -} - -func (x *PrimitivesStruct) GetInt32() int32 { - if x != nil { - return x.Int32 - } - return 0 -} - -func (x *PrimitivesStruct) GetInt32Fixed() int32 { - if x != nil { - return x.Int32Fixed - } - return 0 -} - -func (x *PrimitivesStruct) GetInt64() int64 { - if x != nil { - return x.Int64 - } - return 0 -} - -func (x *PrimitivesStruct) GetInt64Fixed() int64 { - if x != nil { - return x.Int64Fixed - } - return 0 -} - -func (x *PrimitivesStruct) GetInt() int64 { - if x != nil { - return x.Int - } - return 0 -} - -func (x *PrimitivesStruct) GetByte() uint32 { - if x != nil { - return x.Byte - } - return 0 -} - -func (x *PrimitivesStruct) GetUint8() uint32 { - if x != nil { - return x.Uint8 - } - return 0 -} - -func (x *PrimitivesStruct) GetUint16() uint32 { - if x != nil { - return x.Uint16 - } - return 0 -} - -func (x *PrimitivesStruct) GetUint32() uint32 { - if x != nil { - return x.Uint32 - } - return 0 -} - -func (x *PrimitivesStruct) GetUint32Fixed() uint32 { - if x != nil { - return x.Uint32Fixed - } - return 0 -} - -func (x *PrimitivesStruct) GetUint64() uint64 { - if x != nil { - return x.Uint64 - } - return 0 -} - -func (x *PrimitivesStruct) GetUint64Fixed() uint64 { - if x != nil { - return x.Uint64Fixed - } - return 0 -} - -func (x *PrimitivesStruct) GetUint() uint64 { - if x != nil { - return x.Uint - } - return 0 -} - -func (x *PrimitivesStruct) GetStr() string { - if x != nil { - return x.Str - } - return "" -} - -func (x *PrimitivesStruct) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -func (x *PrimitivesStruct) GetTime() *timestamppb.Timestamp { - if x != nil { - return x.Time - } - return nil -} - -func (x *PrimitivesStruct) GetDuration() *durationpb.Duration { - if x != nil { - return x.Duration - } - return nil -} - -func (x *PrimitivesStruct) GetEmpty() *EmptyStruct { - if x != nil { - return x.Empty - } - return nil -} - -type ShortArraysStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TimeAr []*timestamppb.Timestamp `protobuf:"bytes,1,rep,name=time_ar,json=TimeAr,proto3" json:"time_ar,omitempty"` - DurationAr []*durationpb.Duration `protobuf:"bytes,2,rep,name=duration_ar,json=DurationAr,proto3" json:"duration_ar,omitempty"` -} - -func (x *ShortArraysStruct) Reset() { - *x = ShortArraysStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ShortArraysStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ShortArraysStruct) ProtoMessage() {} - -func (x *ShortArraysStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ShortArraysStruct.ProtoReflect.Descriptor instead. -func (*ShortArraysStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{2} -} - -func (x *ShortArraysStruct) GetTimeAr() []*timestamppb.Timestamp { - if x != nil { - return x.TimeAr - } - return nil -} - -func (x *ShortArraysStruct) GetDurationAr() []*durationpb.Duration { - if x != nil { - return x.DurationAr - } - return nil -} - -type ArraysStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8Ar []int32 `protobuf:"zigzag32,1,rep,packed,name=int8_ar,json=Int8Ar,proto3" json:"int8_ar,omitempty"` - Int16Ar []int32 `protobuf:"zigzag32,2,rep,packed,name=int16_ar,json=Int16Ar,proto3" json:"int16_ar,omitempty"` - Int32Ar []int32 `protobuf:"zigzag32,3,rep,packed,name=int32_ar,json=Int32Ar,proto3" json:"int32_ar,omitempty"` - Int32FixedAr []int32 `protobuf:"fixed32,4,rep,packed,name=int32_fixed_ar,json=Int32FixedAr,proto3" json:"int32_fixed_ar,omitempty"` - Int64Ar []int64 `protobuf:"zigzag64,5,rep,packed,name=int64_ar,json=Int64Ar,proto3" json:"int64_ar,omitempty"` - Int64FixedAr []int64 `protobuf:"fixed64,6,rep,packed,name=int64_fixed_ar,json=Int64FixedAr,proto3" json:"int64_fixed_ar,omitempty"` - IntAr []int64 `protobuf:"zigzag64,7,rep,packed,name=int_ar,json=IntAr,proto3" json:"int_ar,omitempty"` - ByteAr []byte `protobuf:"bytes,8,opt,name=byte_ar,json=ByteAr,proto3" json:"byte_ar,omitempty"` - Uint8Ar []byte `protobuf:"bytes,9,opt,name=uint8_ar,json=Uint8Ar,proto3" json:"uint8_ar,omitempty"` - Uint16Ar []uint32 `protobuf:"varint,10,rep,packed,name=uint16_ar,json=Uint16Ar,proto3" json:"uint16_ar,omitempty"` - Uint32Ar []uint32 `protobuf:"varint,11,rep,packed,name=uint32_ar,json=Uint32Ar,proto3" json:"uint32_ar,omitempty"` - Uint32FixedAr []uint32 `protobuf:"fixed32,12,rep,packed,name=uint32_fixed_ar,json=Uint32FixedAr,proto3" json:"uint32_fixed_ar,omitempty"` - Uint64Ar []uint64 `protobuf:"varint,13,rep,packed,name=uint64_ar,json=Uint64Ar,proto3" json:"uint64_ar,omitempty"` - Uint64FixedAr []uint64 `protobuf:"fixed64,14,rep,packed,name=uint64_fixed_ar,json=Uint64FixedAr,proto3" json:"uint64_fixed_ar,omitempty"` - UintAr []uint64 `protobuf:"varint,15,rep,packed,name=uint_ar,json=UintAr,proto3" json:"uint_ar,omitempty"` - StrAr []string `protobuf:"bytes,16,rep,name=str_ar,json=StrAr,proto3" json:"str_ar,omitempty"` - BytesAr [][]byte `protobuf:"bytes,17,rep,name=bytes_ar,json=BytesAr,proto3" json:"bytes_ar,omitempty"` - TimeAr []*timestamppb.Timestamp `protobuf:"bytes,18,rep,name=time_ar,json=TimeAr,proto3" json:"time_ar,omitempty"` - DurationAr []*durationpb.Duration `protobuf:"bytes,19,rep,name=duration_ar,json=DurationAr,proto3" json:"duration_ar,omitempty"` - EmptyAr []*EmptyStruct `protobuf:"bytes,20,rep,name=empty_ar,json=EmptyAr,proto3" json:"empty_ar,omitempty"` -} - -func (x *ArraysStruct) Reset() { - *x = ArraysStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ArraysStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ArraysStruct) ProtoMessage() {} - -func (x *ArraysStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ArraysStruct.ProtoReflect.Descriptor instead. -func (*ArraysStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{3} -} - -func (x *ArraysStruct) GetInt8Ar() []int32 { - if x != nil { - return x.Int8Ar - } - return nil -} - -func (x *ArraysStruct) GetInt16Ar() []int32 { - if x != nil { - return x.Int16Ar - } - return nil -} - -func (x *ArraysStruct) GetInt32Ar() []int32 { - if x != nil { - return x.Int32Ar - } - return nil -} - -func (x *ArraysStruct) GetInt32FixedAr() []int32 { - if x != nil { - return x.Int32FixedAr - } - return nil -} - -func (x *ArraysStruct) GetInt64Ar() []int64 { - if x != nil { - return x.Int64Ar - } - return nil -} - -func (x *ArraysStruct) GetInt64FixedAr() []int64 { - if x != nil { - return x.Int64FixedAr - } - return nil -} - -func (x *ArraysStruct) GetIntAr() []int64 { - if x != nil { - return x.IntAr - } - return nil -} - -func (x *ArraysStruct) GetByteAr() []byte { - if x != nil { - return x.ByteAr - } - return nil -} - -func (x *ArraysStruct) GetUint8Ar() []byte { - if x != nil { - return x.Uint8Ar - } - return nil -} - -func (x *ArraysStruct) GetUint16Ar() []uint32 { - if x != nil { - return x.Uint16Ar - } - return nil -} - -func (x *ArraysStruct) GetUint32Ar() []uint32 { - if x != nil { - return x.Uint32Ar - } - return nil -} - -func (x *ArraysStruct) GetUint32FixedAr() []uint32 { - if x != nil { - return x.Uint32FixedAr - } - return nil -} - -func (x *ArraysStruct) GetUint64Ar() []uint64 { - if x != nil { - return x.Uint64Ar - } - return nil -} - -func (x *ArraysStruct) GetUint64FixedAr() []uint64 { - if x != nil { - return x.Uint64FixedAr - } - return nil -} - -func (x *ArraysStruct) GetUintAr() []uint64 { - if x != nil { - return x.UintAr - } - return nil -} - -func (x *ArraysStruct) GetStrAr() []string { - if x != nil { - return x.StrAr - } - return nil -} - -func (x *ArraysStruct) GetBytesAr() [][]byte { - if x != nil { - return x.BytesAr - } - return nil -} - -func (x *ArraysStruct) GetTimeAr() []*timestamppb.Timestamp { - if x != nil { - return x.TimeAr - } - return nil -} - -func (x *ArraysStruct) GetDurationAr() []*durationpb.Duration { - if x != nil { - return x.DurationAr - } - return nil -} - -func (x *ArraysStruct) GetEmptyAr() []*EmptyStruct { - if x != nil { - return x.EmptyAr - } - return nil -} - -type ArraysArraysStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8ArAr []*TESTS_Int8List `protobuf:"bytes,1,rep,name=int8_ar_ar,json=Int8ArAr,proto3" json:"int8_ar_ar,omitempty"` - Int16ArAr []*TESTS_Int16List `protobuf:"bytes,2,rep,name=int16_ar_ar,json=Int16ArAr,proto3" json:"int16_ar_ar,omitempty"` - Int32ArAr []*TESTS_Int32ValueList `protobuf:"bytes,3,rep,name=int32_ar_ar,json=Int32ArAr,proto3" json:"int32_ar_ar,omitempty"` - Int32FixedArAr []*TESTS_Fixed32Int32ValueList `protobuf:"bytes,4,rep,name=int32_fixed_ar_ar,json=Int32FixedArAr,proto3" json:"int32_fixed_ar_ar,omitempty"` - Int64ArAr []*TESTS_Int64ValueList `protobuf:"bytes,5,rep,name=int64_ar_ar,json=Int64ArAr,proto3" json:"int64_ar_ar,omitempty"` - Int64FixedArAr []*TESTS_Fixed64Int64ValueList `protobuf:"bytes,6,rep,name=int64_fixed_ar_ar,json=Int64FixedArAr,proto3" json:"int64_fixed_ar_ar,omitempty"` - IntArAr []*TESTS_Int64ValueList `protobuf:"bytes,7,rep,name=int_ar_ar,json=IntArAr,proto3" json:"int_ar_ar,omitempty"` - ByteArAr [][]byte `protobuf:"bytes,8,rep,name=byte_ar_ar,json=ByteArAr,proto3" json:"byte_ar_ar,omitempty"` - Uint8ArAr [][]byte `protobuf:"bytes,9,rep,name=uint8_ar_ar,json=Uint8ArAr,proto3" json:"uint8_ar_ar,omitempty"` - Uint16ArAr []*TESTS_UInt16List `protobuf:"bytes,10,rep,name=uint16_ar_ar,json=Uint16ArAr,proto3" json:"uint16_ar_ar,omitempty"` - Uint32ArAr []*TESTS_UInt32ValueList `protobuf:"bytes,11,rep,name=uint32_ar_ar,json=Uint32ArAr,proto3" json:"uint32_ar_ar,omitempty"` - Uint32FixedArAr []*TESTS_Fixed32UInt32ValueList `protobuf:"bytes,12,rep,name=uint32_fixed_ar_ar,json=Uint32FixedArAr,proto3" json:"uint32_fixed_ar_ar,omitempty"` - Uint64ArAr []*TESTS_UInt64ValueList `protobuf:"bytes,13,rep,name=uint64_ar_ar,json=Uint64ArAr,proto3" json:"uint64_ar_ar,omitempty"` - Uint64FixedArAr []*TESTS_Fixed64UInt64ValueList `protobuf:"bytes,14,rep,name=uint64_fixed_ar_ar,json=Uint64FixedArAr,proto3" json:"uint64_fixed_ar_ar,omitempty"` - UintArAr []*TESTS_UInt64ValueList `protobuf:"bytes,15,rep,name=uint_ar_ar,json=UintArAr,proto3" json:"uint_ar_ar,omitempty"` - StrArAr []*TESTS_StringValueList `protobuf:"bytes,16,rep,name=str_ar_ar,json=StrArAr,proto3" json:"str_ar_ar,omitempty"` - BytesArAr []*TESTS_BytesList `protobuf:"bytes,17,rep,name=bytes_ar_ar,json=BytesArAr,proto3" json:"bytes_ar_ar,omitempty"` - TimeArAr []*TESTS_TimestampList `protobuf:"bytes,18,rep,name=time_ar_ar,json=TimeArAr,proto3" json:"time_ar_ar,omitempty"` - DurationArAr []*TESTS_DurationList `protobuf:"bytes,19,rep,name=duration_ar_ar,json=DurationArAr,proto3" json:"duration_ar_ar,omitempty"` - EmptyArAr []*TESTS_EmptyStructList `protobuf:"bytes,20,rep,name=empty_ar_ar,json=EmptyArAr,proto3" json:"empty_ar_ar,omitempty"` -} - -func (x *ArraysArraysStruct) Reset() { - *x = ArraysArraysStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ArraysArraysStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ArraysArraysStruct) ProtoMessage() {} - -func (x *ArraysArraysStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ArraysArraysStruct.ProtoReflect.Descriptor instead. -func (*ArraysArraysStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{4} -} - -func (x *ArraysArraysStruct) GetInt8ArAr() []*TESTS_Int8List { - if x != nil { - return x.Int8ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetInt16ArAr() []*TESTS_Int16List { - if x != nil { - return x.Int16ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetInt32ArAr() []*TESTS_Int32ValueList { - if x != nil { - return x.Int32ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetInt32FixedArAr() []*TESTS_Fixed32Int32ValueList { - if x != nil { - return x.Int32FixedArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetInt64ArAr() []*TESTS_Int64ValueList { - if x != nil { - return x.Int64ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetInt64FixedArAr() []*TESTS_Fixed64Int64ValueList { - if x != nil { - return x.Int64FixedArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetIntArAr() []*TESTS_Int64ValueList { - if x != nil { - return x.IntArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetByteArAr() [][]byte { - if x != nil { - return x.ByteArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUint8ArAr() [][]byte { - if x != nil { - return x.Uint8ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUint16ArAr() []*TESTS_UInt16List { - if x != nil { - return x.Uint16ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUint32ArAr() []*TESTS_UInt32ValueList { - if x != nil { - return x.Uint32ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUint32FixedArAr() []*TESTS_Fixed32UInt32ValueList { - if x != nil { - return x.Uint32FixedArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUint64ArAr() []*TESTS_UInt64ValueList { - if x != nil { - return x.Uint64ArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUint64FixedArAr() []*TESTS_Fixed64UInt64ValueList { - if x != nil { - return x.Uint64FixedArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetUintArAr() []*TESTS_UInt64ValueList { - if x != nil { - return x.UintArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetStrArAr() []*TESTS_StringValueList { - if x != nil { - return x.StrArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetBytesArAr() []*TESTS_BytesList { - if x != nil { - return x.BytesArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetTimeArAr() []*TESTS_TimestampList { - if x != nil { - return x.TimeArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetDurationArAr() []*TESTS_DurationList { - if x != nil { - return x.DurationArAr - } - return nil -} - -func (x *ArraysArraysStruct) GetEmptyArAr() []*TESTS_EmptyStructList { - if x != nil { - return x.EmptyArAr - } - return nil -} - -type SlicesStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8Sl []int32 `protobuf:"zigzag32,1,rep,packed,name=int8_sl,json=Int8Sl,proto3" json:"int8_sl,omitempty"` - Int16Sl []int32 `protobuf:"zigzag32,2,rep,packed,name=int16_sl,json=Int16Sl,proto3" json:"int16_sl,omitempty"` - Int32Sl []int32 `protobuf:"zigzag32,3,rep,packed,name=int32_sl,json=Int32Sl,proto3" json:"int32_sl,omitempty"` - Int32FixedSl []int32 `protobuf:"fixed32,4,rep,packed,name=int32_fixed_sl,json=Int32FixedSl,proto3" json:"int32_fixed_sl,omitempty"` - Int64Sl []int64 `protobuf:"zigzag64,5,rep,packed,name=int64_sl,json=Int64Sl,proto3" json:"int64_sl,omitempty"` - Int64FixedSl []int64 `protobuf:"fixed64,6,rep,packed,name=int64_fixed_sl,json=Int64FixedSl,proto3" json:"int64_fixed_sl,omitempty"` - IntSl []int64 `protobuf:"zigzag64,7,rep,packed,name=int_sl,json=IntSl,proto3" json:"int_sl,omitempty"` - ByteSl []byte `protobuf:"bytes,8,opt,name=byte_sl,json=ByteSl,proto3" json:"byte_sl,omitempty"` - Uint8Sl []byte `protobuf:"bytes,9,opt,name=uint8_sl,json=Uint8Sl,proto3" json:"uint8_sl,omitempty"` - Uint16Sl []uint32 `protobuf:"varint,10,rep,packed,name=uint16_sl,json=Uint16Sl,proto3" json:"uint16_sl,omitempty"` - Uint32Sl []uint32 `protobuf:"varint,11,rep,packed,name=uint32_sl,json=Uint32Sl,proto3" json:"uint32_sl,omitempty"` - Uint32FixedSl []uint32 `protobuf:"fixed32,12,rep,packed,name=uint32_fixed_sl,json=Uint32FixedSl,proto3" json:"uint32_fixed_sl,omitempty"` - Uint64Sl []uint64 `protobuf:"varint,13,rep,packed,name=uint64_sl,json=Uint64Sl,proto3" json:"uint64_sl,omitempty"` - Uint64FixedSl []uint64 `protobuf:"fixed64,14,rep,packed,name=uint64_fixed_sl,json=Uint64FixedSl,proto3" json:"uint64_fixed_sl,omitempty"` - UintSl []uint64 `protobuf:"varint,15,rep,packed,name=uint_sl,json=UintSl,proto3" json:"uint_sl,omitempty"` - StrSl []string `protobuf:"bytes,16,rep,name=str_sl,json=StrSl,proto3" json:"str_sl,omitempty"` - BytesSl [][]byte `protobuf:"bytes,17,rep,name=bytes_sl,json=BytesSl,proto3" json:"bytes_sl,omitempty"` - TimeSl []*timestamppb.Timestamp `protobuf:"bytes,18,rep,name=time_sl,json=TimeSl,proto3" json:"time_sl,omitempty"` - DurationSl []*durationpb.Duration `protobuf:"bytes,19,rep,name=duration_sl,json=DurationSl,proto3" json:"duration_sl,omitempty"` - EmptySl []*EmptyStruct `protobuf:"bytes,20,rep,name=empty_sl,json=EmptySl,proto3" json:"empty_sl,omitempty"` -} - -func (x *SlicesStruct) Reset() { - *x = SlicesStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SlicesStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SlicesStruct) ProtoMessage() {} - -func (x *SlicesStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SlicesStruct.ProtoReflect.Descriptor instead. -func (*SlicesStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{5} -} - -func (x *SlicesStruct) GetInt8Sl() []int32 { - if x != nil { - return x.Int8Sl - } - return nil -} - -func (x *SlicesStruct) GetInt16Sl() []int32 { - if x != nil { - return x.Int16Sl - } - return nil -} - -func (x *SlicesStruct) GetInt32Sl() []int32 { - if x != nil { - return x.Int32Sl - } - return nil -} - -func (x *SlicesStruct) GetInt32FixedSl() []int32 { - if x != nil { - return x.Int32FixedSl - } - return nil -} - -func (x *SlicesStruct) GetInt64Sl() []int64 { - if x != nil { - return x.Int64Sl - } - return nil -} - -func (x *SlicesStruct) GetInt64FixedSl() []int64 { - if x != nil { - return x.Int64FixedSl - } - return nil -} - -func (x *SlicesStruct) GetIntSl() []int64 { - if x != nil { - return x.IntSl - } - return nil -} - -func (x *SlicesStruct) GetByteSl() []byte { - if x != nil { - return x.ByteSl - } - return nil -} - -func (x *SlicesStruct) GetUint8Sl() []byte { - if x != nil { - return x.Uint8Sl - } - return nil -} - -func (x *SlicesStruct) GetUint16Sl() []uint32 { - if x != nil { - return x.Uint16Sl - } - return nil -} - -func (x *SlicesStruct) GetUint32Sl() []uint32 { - if x != nil { - return x.Uint32Sl - } - return nil -} - -func (x *SlicesStruct) GetUint32FixedSl() []uint32 { - if x != nil { - return x.Uint32FixedSl - } - return nil -} - -func (x *SlicesStruct) GetUint64Sl() []uint64 { - if x != nil { - return x.Uint64Sl - } - return nil -} - -func (x *SlicesStruct) GetUint64FixedSl() []uint64 { - if x != nil { - return x.Uint64FixedSl - } - return nil -} - -func (x *SlicesStruct) GetUintSl() []uint64 { - if x != nil { - return x.UintSl - } - return nil -} - -func (x *SlicesStruct) GetStrSl() []string { - if x != nil { - return x.StrSl - } - return nil -} - -func (x *SlicesStruct) GetBytesSl() [][]byte { - if x != nil { - return x.BytesSl - } - return nil -} - -func (x *SlicesStruct) GetTimeSl() []*timestamppb.Timestamp { - if x != nil { - return x.TimeSl - } - return nil -} - -func (x *SlicesStruct) GetDurationSl() []*durationpb.Duration { - if x != nil { - return x.DurationSl - } - return nil -} - -func (x *SlicesStruct) GetEmptySl() []*EmptyStruct { - if x != nil { - return x.EmptySl - } - return nil -} - -type SlicesSlicesStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8SlSl []*TESTS_Int8List `protobuf:"bytes,1,rep,name=int8_sl_sl,json=Int8SlSl,proto3" json:"int8_sl_sl,omitempty"` - Int16SlSl []*TESTS_Int16List `protobuf:"bytes,2,rep,name=int16_sl_sl,json=Int16SlSl,proto3" json:"int16_sl_sl,omitempty"` - Int32SlSl []*TESTS_Int32ValueList `protobuf:"bytes,3,rep,name=int32_sl_sl,json=Int32SlSl,proto3" json:"int32_sl_sl,omitempty"` - Int32FixedSlSl []*TESTS_Fixed32Int32ValueList `protobuf:"bytes,4,rep,name=int32_fixed_sl_sl,json=Int32FixedSlSl,proto3" json:"int32_fixed_sl_sl,omitempty"` - Int64SlSl []*TESTS_Int64ValueList `protobuf:"bytes,5,rep,name=int64_sl_sl,json=Int64SlSl,proto3" json:"int64_sl_sl,omitempty"` - Int64FixedSlSl []*TESTS_Fixed64Int64ValueList `protobuf:"bytes,6,rep,name=int64_fixed_sl_sl,json=Int64FixedSlSl,proto3" json:"int64_fixed_sl_sl,omitempty"` - IntSlSl []*TESTS_Int64ValueList `protobuf:"bytes,7,rep,name=int_sl_sl,json=IntSlSl,proto3" json:"int_sl_sl,omitempty"` - ByteSlSl [][]byte `protobuf:"bytes,8,rep,name=byte_sl_sl,json=ByteSlSl,proto3" json:"byte_sl_sl,omitempty"` - Uint8SlSl [][]byte `protobuf:"bytes,9,rep,name=uint8_sl_sl,json=Uint8SlSl,proto3" json:"uint8_sl_sl,omitempty"` - Uint16SlSl []*TESTS_UInt16List `protobuf:"bytes,10,rep,name=uint16_sl_sl,json=Uint16SlSl,proto3" json:"uint16_sl_sl,omitempty"` - Uint32SlSl []*TESTS_UInt32ValueList `protobuf:"bytes,11,rep,name=uint32_sl_sl,json=Uint32SlSl,proto3" json:"uint32_sl_sl,omitempty"` - Uint32FixedSlSl []*TESTS_Fixed32UInt32ValueList `protobuf:"bytes,12,rep,name=uint32_fixed_sl_sl,json=Uint32FixedSlSl,proto3" json:"uint32_fixed_sl_sl,omitempty"` - Uint64SlSl []*TESTS_UInt64ValueList `protobuf:"bytes,13,rep,name=uint64_sl_sl,json=Uint64SlSl,proto3" json:"uint64_sl_sl,omitempty"` - Uint64FixedSlSl []*TESTS_Fixed64UInt64ValueList `protobuf:"bytes,14,rep,name=uint64_fixed_sl_sl,json=Uint64FixedSlSl,proto3" json:"uint64_fixed_sl_sl,omitempty"` - UintSlSl []*TESTS_UInt64ValueList `protobuf:"bytes,15,rep,name=uint_sl_sl,json=UintSlSl,proto3" json:"uint_sl_sl,omitempty"` - StrSlSl []*TESTS_StringValueList `protobuf:"bytes,16,rep,name=str_sl_sl,json=StrSlSl,proto3" json:"str_sl_sl,omitempty"` - BytesSlSl []*TESTS_BytesList `protobuf:"bytes,17,rep,name=bytes_sl_sl,json=BytesSlSl,proto3" json:"bytes_sl_sl,omitempty"` - TimeSlSl []*TESTS_TimestampList `protobuf:"bytes,18,rep,name=time_sl_sl,json=TimeSlSl,proto3" json:"time_sl_sl,omitempty"` - DurationSlSl []*TESTS_DurationList `protobuf:"bytes,19,rep,name=duration_sl_sl,json=DurationSlSl,proto3" json:"duration_sl_sl,omitempty"` - EmptySlSl []*TESTS_EmptyStructList `protobuf:"bytes,20,rep,name=empty_sl_sl,json=EmptySlSl,proto3" json:"empty_sl_sl,omitempty"` -} - -func (x *SlicesSlicesStruct) Reset() { - *x = SlicesSlicesStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SlicesSlicesStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SlicesSlicesStruct) ProtoMessage() {} - -func (x *SlicesSlicesStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SlicesSlicesStruct.ProtoReflect.Descriptor instead. -func (*SlicesSlicesStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{6} -} - -func (x *SlicesSlicesStruct) GetInt8SlSl() []*TESTS_Int8List { - if x != nil { - return x.Int8SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetInt16SlSl() []*TESTS_Int16List { - if x != nil { - return x.Int16SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetInt32SlSl() []*TESTS_Int32ValueList { - if x != nil { - return x.Int32SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetInt32FixedSlSl() []*TESTS_Fixed32Int32ValueList { - if x != nil { - return x.Int32FixedSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetInt64SlSl() []*TESTS_Int64ValueList { - if x != nil { - return x.Int64SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetInt64FixedSlSl() []*TESTS_Fixed64Int64ValueList { - if x != nil { - return x.Int64FixedSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetIntSlSl() []*TESTS_Int64ValueList { - if x != nil { - return x.IntSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetByteSlSl() [][]byte { - if x != nil { - return x.ByteSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUint8SlSl() [][]byte { - if x != nil { - return x.Uint8SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUint16SlSl() []*TESTS_UInt16List { - if x != nil { - return x.Uint16SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUint32SlSl() []*TESTS_UInt32ValueList { - if x != nil { - return x.Uint32SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUint32FixedSlSl() []*TESTS_Fixed32UInt32ValueList { - if x != nil { - return x.Uint32FixedSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUint64SlSl() []*TESTS_UInt64ValueList { - if x != nil { - return x.Uint64SlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUint64FixedSlSl() []*TESTS_Fixed64UInt64ValueList { - if x != nil { - return x.Uint64FixedSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetUintSlSl() []*TESTS_UInt64ValueList { - if x != nil { - return x.UintSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetStrSlSl() []*TESTS_StringValueList { - if x != nil { - return x.StrSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetBytesSlSl() []*TESTS_BytesList { - if x != nil { - return x.BytesSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetTimeSlSl() []*TESTS_TimestampList { - if x != nil { - return x.TimeSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetDurationSlSl() []*TESTS_DurationList { - if x != nil { - return x.DurationSlSl - } - return nil -} - -func (x *SlicesSlicesStruct) GetEmptySlSl() []*TESTS_EmptyStructList { - if x != nil { - return x.EmptySlSl - } - return nil -} - -type PointersStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8Pt int32 `protobuf:"zigzag32,1,opt,name=int8_pt,json=Int8Pt,proto3" json:"int8_pt,omitempty"` - Int16Pt int32 `protobuf:"zigzag32,2,opt,name=int16_pt,json=Int16Pt,proto3" json:"int16_pt,omitempty"` - Int32Pt int32 `protobuf:"zigzag32,3,opt,name=int32_pt,json=Int32Pt,proto3" json:"int32_pt,omitempty"` - Int32FixedPt int32 `protobuf:"fixed32,4,opt,name=int32_fixed_pt,json=Int32FixedPt,proto3" json:"int32_fixed_pt,omitempty"` - Int64Pt int64 `protobuf:"zigzag64,5,opt,name=int64_pt,json=Int64Pt,proto3" json:"int64_pt,omitempty"` - Int64FixedPt int64 `protobuf:"fixed64,6,opt,name=int64_fixed_pt,json=Int64FixedPt,proto3" json:"int64_fixed_pt,omitempty"` - IntPt int64 `protobuf:"zigzag64,7,opt,name=int_pt,json=IntPt,proto3" json:"int_pt,omitempty"` - BytePt uint32 `protobuf:"varint,8,opt,name=byte_pt,json=BytePt,proto3" json:"byte_pt,omitempty"` - Uint8Pt uint32 `protobuf:"varint,9,opt,name=uint8_pt,json=Uint8Pt,proto3" json:"uint8_pt,omitempty"` - Uint16Pt uint32 `protobuf:"varint,10,opt,name=uint16_pt,json=Uint16Pt,proto3" json:"uint16_pt,omitempty"` - Uint32Pt uint32 `protobuf:"varint,11,opt,name=uint32_pt,json=Uint32Pt,proto3" json:"uint32_pt,omitempty"` - Uint32FixedPt uint32 `protobuf:"fixed32,12,opt,name=uint32_fixed_pt,json=Uint32FixedPt,proto3" json:"uint32_fixed_pt,omitempty"` - Uint64Pt uint64 `protobuf:"varint,13,opt,name=uint64_pt,json=Uint64Pt,proto3" json:"uint64_pt,omitempty"` - Uint64FixedPt uint64 `protobuf:"fixed64,14,opt,name=uint64_fixed_pt,json=Uint64FixedPt,proto3" json:"uint64_fixed_pt,omitempty"` - UintPt uint64 `protobuf:"varint,15,opt,name=uint_pt,json=UintPt,proto3" json:"uint_pt,omitempty"` - StrPt string `protobuf:"bytes,16,opt,name=str_pt,json=StrPt,proto3" json:"str_pt,omitempty"` - BytesPt []byte `protobuf:"bytes,17,opt,name=bytes_pt,json=BytesPt,proto3" json:"bytes_pt,omitempty"` - TimePt *timestamppb.Timestamp `protobuf:"bytes,18,opt,name=time_pt,json=TimePt,proto3" json:"time_pt,omitempty"` - DurationPt *durationpb.Duration `protobuf:"bytes,19,opt,name=duration_pt,json=DurationPt,proto3" json:"duration_pt,omitempty"` - EmptyPt *EmptyStruct `protobuf:"bytes,20,opt,name=empty_pt,json=EmptyPt,proto3" json:"empty_pt,omitempty"` -} - -func (x *PointersStruct) Reset() { - *x = PointersStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PointersStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PointersStruct) ProtoMessage() {} - -func (x *PointersStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PointersStruct.ProtoReflect.Descriptor instead. -func (*PointersStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{7} -} - -func (x *PointersStruct) GetInt8Pt() int32 { - if x != nil { - return x.Int8Pt - } - return 0 -} - -func (x *PointersStruct) GetInt16Pt() int32 { - if x != nil { - return x.Int16Pt - } - return 0 -} - -func (x *PointersStruct) GetInt32Pt() int32 { - if x != nil { - return x.Int32Pt - } - return 0 -} - -func (x *PointersStruct) GetInt32FixedPt() int32 { - if x != nil { - return x.Int32FixedPt - } - return 0 -} - -func (x *PointersStruct) GetInt64Pt() int64 { - if x != nil { - return x.Int64Pt - } - return 0 -} - -func (x *PointersStruct) GetInt64FixedPt() int64 { - if x != nil { - return x.Int64FixedPt - } - return 0 -} - -func (x *PointersStruct) GetIntPt() int64 { - if x != nil { - return x.IntPt - } - return 0 -} - -func (x *PointersStruct) GetBytePt() uint32 { - if x != nil { - return x.BytePt - } - return 0 -} - -func (x *PointersStruct) GetUint8Pt() uint32 { - if x != nil { - return x.Uint8Pt - } - return 0 -} - -func (x *PointersStruct) GetUint16Pt() uint32 { - if x != nil { - return x.Uint16Pt - } - return 0 -} - -func (x *PointersStruct) GetUint32Pt() uint32 { - if x != nil { - return x.Uint32Pt - } - return 0 -} - -func (x *PointersStruct) GetUint32FixedPt() uint32 { - if x != nil { - return x.Uint32FixedPt - } - return 0 -} - -func (x *PointersStruct) GetUint64Pt() uint64 { - if x != nil { - return x.Uint64Pt - } - return 0 -} - -func (x *PointersStruct) GetUint64FixedPt() uint64 { - if x != nil { - return x.Uint64FixedPt - } - return 0 -} - -func (x *PointersStruct) GetUintPt() uint64 { - if x != nil { - return x.UintPt - } - return 0 -} - -func (x *PointersStruct) GetStrPt() string { - if x != nil { - return x.StrPt - } - return "" -} - -func (x *PointersStruct) GetBytesPt() []byte { - if x != nil { - return x.BytesPt - } - return nil -} - -func (x *PointersStruct) GetTimePt() *timestamppb.Timestamp { - if x != nil { - return x.TimePt - } - return nil -} - -func (x *PointersStruct) GetDurationPt() *durationpb.Duration { - if x != nil { - return x.DurationPt - } - return nil -} - -func (x *PointersStruct) GetEmptyPt() *EmptyStruct { - if x != nil { - return x.EmptyPt - } - return nil -} - -type PointerSlicesStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8PtSl []int32 `protobuf:"zigzag32,1,rep,packed,name=int8_pt_sl,json=Int8PtSl,proto3" json:"int8_pt_sl,omitempty"` - Int16PtSl []int32 `protobuf:"zigzag32,2,rep,packed,name=int16_pt_sl,json=Int16PtSl,proto3" json:"int16_pt_sl,omitempty"` - Int32PtSl []int32 `protobuf:"zigzag32,3,rep,packed,name=int32_pt_sl,json=Int32PtSl,proto3" json:"int32_pt_sl,omitempty"` - Int32FixedPtSl []int32 `protobuf:"fixed32,4,rep,packed,name=int32_fixed_pt_sl,json=Int32FixedPtSl,proto3" json:"int32_fixed_pt_sl,omitempty"` - Int64PtSl []int64 `protobuf:"zigzag64,5,rep,packed,name=int64_pt_sl,json=Int64PtSl,proto3" json:"int64_pt_sl,omitempty"` - Int64FixedPtSl []int64 `protobuf:"fixed64,6,rep,packed,name=int64_fixed_pt_sl,json=Int64FixedPtSl,proto3" json:"int64_fixed_pt_sl,omitempty"` - IntPtSl []int64 `protobuf:"zigzag64,7,rep,packed,name=int_pt_sl,json=IntPtSl,proto3" json:"int_pt_sl,omitempty"` - BytePtSl []byte `protobuf:"bytes,8,opt,name=byte_pt_sl,json=BytePtSl,proto3" json:"byte_pt_sl,omitempty"` - Uint8PtSl []byte `protobuf:"bytes,9,opt,name=uint8_pt_sl,json=Uint8PtSl,proto3" json:"uint8_pt_sl,omitempty"` - Uint16PtSl []uint32 `protobuf:"varint,10,rep,packed,name=uint16_pt_sl,json=Uint16PtSl,proto3" json:"uint16_pt_sl,omitempty"` - Uint32PtSl []uint32 `protobuf:"varint,11,rep,packed,name=uint32_pt_sl,json=Uint32PtSl,proto3" json:"uint32_pt_sl,omitempty"` - Uint32FixedPtSl []uint32 `protobuf:"fixed32,12,rep,packed,name=uint32_fixed_pt_sl,json=Uint32FixedPtSl,proto3" json:"uint32_fixed_pt_sl,omitempty"` - Uint64PtSl []uint64 `protobuf:"varint,13,rep,packed,name=uint64_pt_sl,json=Uint64PtSl,proto3" json:"uint64_pt_sl,omitempty"` - Uint64FixedPtSl []uint64 `protobuf:"fixed64,14,rep,packed,name=uint64_fixed_pt_sl,json=Uint64FixedPtSl,proto3" json:"uint64_fixed_pt_sl,omitempty"` - UintPtSl []uint64 `protobuf:"varint,15,rep,packed,name=uint_pt_sl,json=UintPtSl,proto3" json:"uint_pt_sl,omitempty"` - StrPtSl []string `protobuf:"bytes,16,rep,name=str_pt_sl,json=StrPtSl,proto3" json:"str_pt_sl,omitempty"` - BytesPtSl [][]byte `protobuf:"bytes,17,rep,name=bytes_pt_sl,json=BytesPtSl,proto3" json:"bytes_pt_sl,omitempty"` - TimePtSl []*timestamppb.Timestamp `protobuf:"bytes,18,rep,name=time_pt_sl,json=TimePtSl,proto3" json:"time_pt_sl,omitempty"` - DurationPtSl []*durationpb.Duration `protobuf:"bytes,19,rep,name=duration_pt_sl,json=DurationPtSl,proto3" json:"duration_pt_sl,omitempty"` - EmptyPtSl []*EmptyStruct `protobuf:"bytes,20,rep,name=empty_pt_sl,json=EmptyPtSl,proto3" json:"empty_pt_sl,omitempty"` -} - -func (x *PointerSlicesStruct) Reset() { - *x = PointerSlicesStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PointerSlicesStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PointerSlicesStruct) ProtoMessage() {} - -func (x *PointerSlicesStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PointerSlicesStruct.ProtoReflect.Descriptor instead. -func (*PointerSlicesStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{8} -} - -func (x *PointerSlicesStruct) GetInt8PtSl() []int32 { - if x != nil { - return x.Int8PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetInt16PtSl() []int32 { - if x != nil { - return x.Int16PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetInt32PtSl() []int32 { - if x != nil { - return x.Int32PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetInt32FixedPtSl() []int32 { - if x != nil { - return x.Int32FixedPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetInt64PtSl() []int64 { - if x != nil { - return x.Int64PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetInt64FixedPtSl() []int64 { - if x != nil { - return x.Int64FixedPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetIntPtSl() []int64 { - if x != nil { - return x.IntPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetBytePtSl() []byte { - if x != nil { - return x.BytePtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUint8PtSl() []byte { - if x != nil { - return x.Uint8PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUint16PtSl() []uint32 { - if x != nil { - return x.Uint16PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUint32PtSl() []uint32 { - if x != nil { - return x.Uint32PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUint32FixedPtSl() []uint32 { - if x != nil { - return x.Uint32FixedPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUint64PtSl() []uint64 { - if x != nil { - return x.Uint64PtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUint64FixedPtSl() []uint64 { - if x != nil { - return x.Uint64FixedPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetUintPtSl() []uint64 { - if x != nil { - return x.UintPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetStrPtSl() []string { - if x != nil { - return x.StrPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetBytesPtSl() [][]byte { - if x != nil { - return x.BytesPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetTimePtSl() []*timestamppb.Timestamp { - if x != nil { - return x.TimePtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetDurationPtSl() []*durationpb.Duration { - if x != nil { - return x.DurationPtSl - } - return nil -} - -func (x *PointerSlicesStruct) GetEmptyPtSl() []*EmptyStruct { - if x != nil { - return x.EmptyPtSl - } - return nil -} - -type ComplexSt struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PrField *PrimitivesStruct `protobuf:"bytes,1,opt,name=pr_field,json=PrField,proto3" json:"pr_field,omitempty"` - ArField *ArraysStruct `protobuf:"bytes,2,opt,name=ar_field,json=ArField,proto3" json:"ar_field,omitempty"` - SlField *SlicesStruct `protobuf:"bytes,3,opt,name=sl_field,json=SlField,proto3" json:"sl_field,omitempty"` - PtField *PointersStruct `protobuf:"bytes,4,opt,name=pt_field,json=PtField,proto3" json:"pt_field,omitempty"` -} - -func (x *ComplexSt) Reset() { - *x = ComplexSt{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ComplexSt) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ComplexSt) ProtoMessage() {} - -func (x *ComplexSt) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ComplexSt.ProtoReflect.Descriptor instead. -func (*ComplexSt) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{9} -} - -func (x *ComplexSt) GetPrField() *PrimitivesStruct { - if x != nil { - return x.PrField - } - return nil -} - -func (x *ComplexSt) GetArField() *ArraysStruct { - if x != nil { - return x.ArField - } - return nil -} - -func (x *ComplexSt) GetSlField() *SlicesStruct { - if x != nil { - return x.SlField - } - return nil -} - -func (x *ComplexSt) GetPtField() *PointersStruct { - if x != nil { - return x.PtField - } - return nil -} - -type EmbeddedSt1 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PrimitivesStruct *PrimitivesStruct `protobuf:"bytes,1,opt,name=primitives_struct,json=PrimitivesStruct,proto3" json:"primitives_struct,omitempty"` -} - -func (x *EmbeddedSt1) Reset() { - *x = EmbeddedSt1{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmbeddedSt1) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmbeddedSt1) ProtoMessage() {} - -func (x *EmbeddedSt1) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmbeddedSt1.ProtoReflect.Descriptor instead. -func (*EmbeddedSt1) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{10} -} - -func (x *EmbeddedSt1) GetPrimitivesStruct() *PrimitivesStruct { - if x != nil { - return x.PrimitivesStruct - } - return nil -} - -type EmbeddedSt2 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PrimitivesStruct *PrimitivesStruct `protobuf:"bytes,1,opt,name=primitives_struct,json=PrimitivesStruct,proto3" json:"primitives_struct,omitempty"` - ArraysStruct *ArraysStruct `protobuf:"bytes,2,opt,name=arrays_struct,json=ArraysStruct,proto3" json:"arrays_struct,omitempty"` - SlicesStruct *SlicesStruct `protobuf:"bytes,3,opt,name=slices_struct,json=SlicesStruct,proto3" json:"slices_struct,omitempty"` - PointersStruct *PointersStruct `protobuf:"bytes,4,opt,name=pointers_struct,json=PointersStruct,proto3" json:"pointers_struct,omitempty"` -} - -func (x *EmbeddedSt2) Reset() { - *x = EmbeddedSt2{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmbeddedSt2) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmbeddedSt2) ProtoMessage() {} - -func (x *EmbeddedSt2) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmbeddedSt2.ProtoReflect.Descriptor instead. -func (*EmbeddedSt2) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{11} -} - -func (x *EmbeddedSt2) GetPrimitivesStruct() *PrimitivesStruct { - if x != nil { - return x.PrimitivesStruct - } - return nil -} - -func (x *EmbeddedSt2) GetArraysStruct() *ArraysStruct { - if x != nil { - return x.ArraysStruct - } - return nil -} - -func (x *EmbeddedSt2) GetSlicesStruct() *SlicesStruct { - if x != nil { - return x.SlicesStruct - } - return nil -} - -func (x *EmbeddedSt2) GetPointersStruct() *PointersStruct { - if x != nil { - return x.PointersStruct - } - return nil -} - -type EmbeddedSt3 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PrimitivesStruct *PrimitivesStruct `protobuf:"bytes,1,opt,name=primitives_struct,json=PrimitivesStruct,proto3" json:"primitives_struct,omitempty"` - ArraysStruct *ArraysStruct `protobuf:"bytes,2,opt,name=arrays_struct,json=ArraysStruct,proto3" json:"arrays_struct,omitempty"` - SlicesStruct *SlicesStruct `protobuf:"bytes,3,opt,name=slices_struct,json=SlicesStruct,proto3" json:"slices_struct,omitempty"` - PointersStruct *PointersStruct `protobuf:"bytes,4,opt,name=pointers_struct,json=PointersStruct,proto3" json:"pointers_struct,omitempty"` - EmptyStruct *EmptyStruct `protobuf:"bytes,5,opt,name=empty_struct,json=EmptyStruct,proto3" json:"empty_struct,omitempty"` -} - -func (x *EmbeddedSt3) Reset() { - *x = EmbeddedSt3{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmbeddedSt3) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmbeddedSt3) ProtoMessage() {} - -func (x *EmbeddedSt3) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmbeddedSt3.ProtoReflect.Descriptor instead. -func (*EmbeddedSt3) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{12} -} - -func (x *EmbeddedSt3) GetPrimitivesStruct() *PrimitivesStruct { - if x != nil { - return x.PrimitivesStruct - } - return nil -} - -func (x *EmbeddedSt3) GetArraysStruct() *ArraysStruct { - if x != nil { - return x.ArraysStruct - } - return nil -} - -func (x *EmbeddedSt3) GetSlicesStruct() *SlicesStruct { - if x != nil { - return x.SlicesStruct - } - return nil -} - -func (x *EmbeddedSt3) GetPointersStruct() *PointersStruct { - if x != nil { - return x.PointersStruct - } - return nil -} - -func (x *EmbeddedSt3) GetEmptyStruct() *EmptyStruct { - if x != nil { - return x.EmptyStruct - } - return nil -} - -type EmbeddedSt4 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Foo1 int64 `protobuf:"zigzag64,1,opt,name=foo1,json=Foo1,proto3" json:"foo1,omitempty"` - PrimitivesStruct *PrimitivesStruct `protobuf:"bytes,2,opt,name=primitives_struct,json=PrimitivesStruct,proto3" json:"primitives_struct,omitempty"` - Foo2 string `protobuf:"bytes,3,opt,name=foo2,json=Foo2,proto3" json:"foo2,omitempty"` - ArraysStructField *ArraysStruct `protobuf:"bytes,4,opt,name=arrays_struct_field,json=ArraysStructField,proto3" json:"arrays_struct_field,omitempty"` - Foo3 []byte `protobuf:"bytes,5,opt,name=foo3,json=Foo3,proto3" json:"foo3,omitempty"` - SlicesStruct *SlicesStruct `protobuf:"bytes,6,opt,name=slices_struct,json=SlicesStruct,proto3" json:"slices_struct,omitempty"` - Foo4 bool `protobuf:"varint,7,opt,name=foo4,json=Foo4,proto3" json:"foo4,omitempty"` - PointersStructField *PointersStruct `protobuf:"bytes,8,opt,name=pointers_struct_field,json=PointersStructField,proto3" json:"pointers_struct_field,omitempty"` - Foo5 uint64 `protobuf:"varint,9,opt,name=foo5,json=Foo5,proto3" json:"foo5,omitempty"` -} - -func (x *EmbeddedSt4) Reset() { - *x = EmbeddedSt4{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmbeddedSt4) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmbeddedSt4) ProtoMessage() {} - -func (x *EmbeddedSt4) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmbeddedSt4.ProtoReflect.Descriptor instead. -func (*EmbeddedSt4) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{13} -} - -func (x *EmbeddedSt4) GetFoo1() int64 { - if x != nil { - return x.Foo1 - } - return 0 -} - -func (x *EmbeddedSt4) GetPrimitivesStruct() *PrimitivesStruct { - if x != nil { - return x.PrimitivesStruct - } - return nil -} - -func (x *EmbeddedSt4) GetFoo2() string { - if x != nil { - return x.Foo2 - } - return "" -} - -func (x *EmbeddedSt4) GetArraysStructField() *ArraysStruct { - if x != nil { - return x.ArraysStructField - } - return nil -} - -func (x *EmbeddedSt4) GetFoo3() []byte { - if x != nil { - return x.Foo3 - } - return nil -} - -func (x *EmbeddedSt4) GetSlicesStruct() *SlicesStruct { - if x != nil { - return x.SlicesStruct - } - return nil -} - -func (x *EmbeddedSt4) GetFoo4() bool { - if x != nil { - return x.Foo4 - } - return false -} - -func (x *EmbeddedSt4) GetPointersStructField() *PointersStruct { - if x != nil { - return x.PointersStructField - } - return nil -} - -func (x *EmbeddedSt4) GetFoo5() uint64 { - if x != nil { - return x.Foo5 - } - return 0 -} - -type EmbeddedSt5NameOverride struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Foo1 int64 `protobuf:"zigzag64,1,opt,name=foo1,json=Foo1,proto3" json:"foo1,omitempty"` - PrimitivesStruct *PrimitivesStruct `protobuf:"bytes,2,opt,name=primitives_struct,json=PrimitivesStruct,proto3" json:"primitives_struct,omitempty"` - Foo2 string `protobuf:"bytes,3,opt,name=foo2,json=Foo2,proto3" json:"foo2,omitempty"` - ArraysStructField *ArraysStruct `protobuf:"bytes,4,opt,name=arrays_struct_field,json=ArraysStructField,proto3" json:"arrays_struct_field,omitempty"` - Foo3 []byte `protobuf:"bytes,5,opt,name=foo3,json=Foo3,proto3" json:"foo3,omitempty"` - SlicesStruct *SlicesStruct `protobuf:"bytes,6,opt,name=slices_struct,json=SlicesStruct,proto3" json:"slices_struct,omitempty"` - Foo4 bool `protobuf:"varint,7,opt,name=foo4,json=Foo4,proto3" json:"foo4,omitempty"` - PointersStructField *PointersStruct `protobuf:"bytes,8,opt,name=pointers_struct_field,json=PointersStructField,proto3" json:"pointers_struct_field,omitempty"` - Foo5 uint64 `protobuf:"varint,9,opt,name=foo5,json=Foo5,proto3" json:"foo5,omitempty"` -} - -func (x *EmbeddedSt5NameOverride) Reset() { - *x = EmbeddedSt5NameOverride{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmbeddedSt5NameOverride) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmbeddedSt5NameOverride) ProtoMessage() {} - -func (x *EmbeddedSt5NameOverride) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmbeddedSt5NameOverride.ProtoReflect.Descriptor instead. -func (*EmbeddedSt5NameOverride) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{14} -} - -func (x *EmbeddedSt5NameOverride) GetFoo1() int64 { - if x != nil { - return x.Foo1 - } - return 0 -} - -func (x *EmbeddedSt5NameOverride) GetPrimitivesStruct() *PrimitivesStruct { - if x != nil { - return x.PrimitivesStruct - } - return nil -} - -func (x *EmbeddedSt5NameOverride) GetFoo2() string { - if x != nil { - return x.Foo2 - } - return "" -} - -func (x *EmbeddedSt5NameOverride) GetArraysStructField() *ArraysStruct { - if x != nil { - return x.ArraysStructField - } - return nil -} - -func (x *EmbeddedSt5NameOverride) GetFoo3() []byte { - if x != nil { - return x.Foo3 - } - return nil -} - -func (x *EmbeddedSt5NameOverride) GetSlicesStruct() *SlicesStruct { - if x != nil { - return x.SlicesStruct - } - return nil -} - -func (x *EmbeddedSt5NameOverride) GetFoo4() bool { - if x != nil { - return x.Foo4 - } - return false -} - -func (x *EmbeddedSt5NameOverride) GetPointersStructField() *PointersStruct { - if x != nil { - return x.PointersStructField - } - return nil -} - -func (x *EmbeddedSt5NameOverride) GetFoo5() uint64 { - if x != nil { - return x.Foo5 - } - return 0 -} - -type AminoMarshalerStruct1 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - C int64 `protobuf:"zigzag64,1,opt,name=c,json=C,proto3" json:"c,omitempty"` - D int64 `protobuf:"zigzag64,2,opt,name=d,json=D,proto3" json:"d,omitempty"` -} - -func (x *AminoMarshalerStruct1) Reset() { - *x = AminoMarshalerStruct1{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerStruct1) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerStruct1) ProtoMessage() {} - -func (x *AminoMarshalerStruct1) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerStruct1.ProtoReflect.Descriptor instead. -func (*AminoMarshalerStruct1) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{15} -} - -func (x *AminoMarshalerStruct1) GetC() int64 { - if x != nil { - return x.C - } - return 0 -} - -func (x *AminoMarshalerStruct1) GetD() int64 { - if x != nil { - return x.D - } - return 0 -} - -type ReprStruct1 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - C int64 `protobuf:"zigzag64,1,opt,name=c,json=C,proto3" json:"c,omitempty"` - D int64 `protobuf:"zigzag64,2,opt,name=d,json=D,proto3" json:"d,omitempty"` -} - -func (x *ReprStruct1) Reset() { - *x = ReprStruct1{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReprStruct1) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReprStruct1) ProtoMessage() {} - -func (x *ReprStruct1) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ReprStruct1.ProtoReflect.Descriptor instead. -func (*ReprStruct1) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{16} -} - -func (x *ReprStruct1) GetC() int64 { - if x != nil { - return x.C - } - return 0 -} - -func (x *ReprStruct1) GetD() int64 { - if x != nil { - return x.D - } - return 0 -} - -type AminoMarshalerStruct2 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*ReprElem2 `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` -} - -func (x *AminoMarshalerStruct2) Reset() { - *x = AminoMarshalerStruct2{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerStruct2) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerStruct2) ProtoMessage() {} - -func (x *AminoMarshalerStruct2) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerStruct2.ProtoReflect.Descriptor instead. -func (*AminoMarshalerStruct2) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{17} -} - -func (x *AminoMarshalerStruct2) GetValue() []*ReprElem2 { - if x != nil { - return x.Value - } - return nil -} - -type ReprElem2 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Key string `protobuf:"bytes,1,opt,name=key,json=Key,proto3" json:"key,omitempty"` - Value *anypb.Any `protobuf:"bytes,2,opt,name=value,json=Value,proto3" json:"value,omitempty"` -} - -func (x *ReprElem2) Reset() { - *x = ReprElem2{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReprElem2) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReprElem2) ProtoMessage() {} - -func (x *ReprElem2) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ReprElem2.ProtoReflect.Descriptor instead. -func (*ReprElem2) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{18} -} - -func (x *ReprElem2) GetKey() string { - if x != nil { - return x.Key - } - return "" -} - -func (x *ReprElem2) GetValue() *anypb.Any { - if x != nil { - return x.Value - } - return nil -} - -type AminoMarshalerStruct3 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value int32 `protobuf:"zigzag32,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *AminoMarshalerStruct3) Reset() { - *x = AminoMarshalerStruct3{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerStruct3) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerStruct3) ProtoMessage() {} - -func (x *AminoMarshalerStruct3) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerStruct3.ProtoReflect.Descriptor instead. -func (*AminoMarshalerStruct3) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{19} -} - -func (x *AminoMarshalerStruct3) GetValue() int32 { - if x != nil { - return x.Value - } - return 0 -} - -type AminoMarshalerInt4 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - A int32 `protobuf:"zigzag32,1,opt,name=a,json=A,proto3" json:"a,omitempty"` -} - -func (x *AminoMarshalerInt4) Reset() { - *x = AminoMarshalerInt4{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerInt4) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerInt4) ProtoMessage() {} - -func (x *AminoMarshalerInt4) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerInt4.ProtoReflect.Descriptor instead. -func (*AminoMarshalerInt4) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{20} -} - -func (x *AminoMarshalerInt4) GetA() int32 { - if x != nil { - return x.A - } - return 0 -} - -type AminoMarshalerInt5 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *AminoMarshalerInt5) Reset() { - *x = AminoMarshalerInt5{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerInt5) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerInt5) ProtoMessage() {} - -func (x *AminoMarshalerInt5) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerInt5.ProtoReflect.Descriptor instead. -func (*AminoMarshalerInt5) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{21} -} - -func (x *AminoMarshalerInt5) GetValue() string { - if x != nil { - return x.Value - } - return "" -} - -type AminoMarshalerStruct6 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*AminoMarshalerStruct1 `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` -} - -func (x *AminoMarshalerStruct6) Reset() { - *x = AminoMarshalerStruct6{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerStruct6) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerStruct6) ProtoMessage() {} - -func (x *AminoMarshalerStruct6) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerStruct6.ProtoReflect.Descriptor instead. -func (*AminoMarshalerStruct6) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{22} -} - -func (x *AminoMarshalerStruct6) GetValue() []*AminoMarshalerStruct1 { - if x != nil { - return x.Value - } - return nil -} - -type AminoMarshalerStruct7 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *AminoMarshalerStruct7) Reset() { - *x = AminoMarshalerStruct7{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AminoMarshalerStruct7) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AminoMarshalerStruct7) ProtoMessage() {} - -func (x *AminoMarshalerStruct7) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AminoMarshalerStruct7.ProtoReflect.Descriptor instead. -func (*AminoMarshalerStruct7) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{23} -} - -func (x *AminoMarshalerStruct7) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - -type ReprElem7 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *ReprElem7) Reset() { - *x = ReprElem7{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReprElem7) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReprElem7) ProtoMessage() {} - -func (x *ReprElem7) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ReprElem7.ProtoReflect.Descriptor instead. -func (*ReprElem7) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{24} -} - -func (x *ReprElem7) GetValue() uint32 { - if x != nil { - return x.Value - } - return 0 -} - -type IntDef struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value int64 `protobuf:"zigzag64,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *IntDef) Reset() { - *x = IntDef{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IntDef) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IntDef) ProtoMessage() {} - -func (x *IntDef) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IntDef.ProtoReflect.Descriptor instead. -func (*IntDef) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{25} -} - -func (x *IntDef) GetValue() int64 { - if x != nil { - return x.Value - } - return 0 -} - -type IntAr struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int64 `protobuf:"zigzag64,1,rep,packed,name=value,proto3" json:"value,omitempty"` -} - -func (x *IntAr) Reset() { - *x = IntAr{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IntAr) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IntAr) ProtoMessage() {} - -func (x *IntAr) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IntAr.ProtoReflect.Descriptor instead. -func (*IntAr) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{26} -} - -func (x *IntAr) GetValue() []int64 { - if x != nil { - return x.Value - } - return nil -} - -type IntSl struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int64 `protobuf:"zigzag64,1,rep,packed,name=value,proto3" json:"value,omitempty"` -} - -func (x *IntSl) Reset() { - *x = IntSl{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IntSl) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IntSl) ProtoMessage() {} - -func (x *IntSl) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IntSl.ProtoReflect.Descriptor instead. -func (*IntSl) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{27} -} - -func (x *IntSl) GetValue() []int64 { - if x != nil { - return x.Value - } - return nil -} - -type ByteAr struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *ByteAr) Reset() { - *x = ByteAr{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ByteAr) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ByteAr) ProtoMessage() {} - -func (x *ByteAr) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ByteAr.ProtoReflect.Descriptor instead. -func (*ByteAr) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{28} -} - -func (x *ByteAr) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - -type ByteSl struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *ByteSl) Reset() { - *x = ByteSl{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ByteSl) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ByteSl) ProtoMessage() {} - -func (x *ByteSl) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ByteSl.ProtoReflect.Descriptor instead. -func (*ByteSl) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{29} -} - -func (x *ByteSl) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - -type PrimitivesStructDef struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int8 int32 `protobuf:"zigzag32,1,opt,name=int8,json=Int8,proto3" json:"int8,omitempty"` - Int16 int32 `protobuf:"zigzag32,2,opt,name=int16,json=Int16,proto3" json:"int16,omitempty"` - Int32 int32 `protobuf:"zigzag32,3,opt,name=int32,json=Int32,proto3" json:"int32,omitempty"` - Int32Fixed int32 `protobuf:"fixed32,4,opt,name=int32_fixed,json=Int32Fixed,proto3" json:"int32_fixed,omitempty"` - Int64 int64 `protobuf:"zigzag64,5,opt,name=int64,json=Int64,proto3" json:"int64,omitempty"` - Int64Fixed int64 `protobuf:"fixed64,6,opt,name=int64_fixed,json=Int64Fixed,proto3" json:"int64_fixed,omitempty"` - Int int64 `protobuf:"zigzag64,7,opt,name=int,json=Int,proto3" json:"int,omitempty"` - Byte uint32 `protobuf:"varint,8,opt,name=byte,json=Byte,proto3" json:"byte,omitempty"` - Uint8 uint32 `protobuf:"varint,9,opt,name=uint8,json=Uint8,proto3" json:"uint8,omitempty"` - Uint16 uint32 `protobuf:"varint,10,opt,name=uint16,json=Uint16,proto3" json:"uint16,omitempty"` - Uint32 uint32 `protobuf:"varint,11,opt,name=uint32,json=Uint32,proto3" json:"uint32,omitempty"` - Uint32Fixed uint32 `protobuf:"fixed32,12,opt,name=uint32_fixed,json=Uint32Fixed,proto3" json:"uint32_fixed,omitempty"` - Uint64 uint64 `protobuf:"varint,13,opt,name=uint64,json=Uint64,proto3" json:"uint64,omitempty"` - Uint64Fixed uint64 `protobuf:"fixed64,14,opt,name=uint64_fixed,json=Uint64Fixed,proto3" json:"uint64_fixed,omitempty"` - Uint uint64 `protobuf:"varint,15,opt,name=uint,json=Uint,proto3" json:"uint,omitempty"` - Str string `protobuf:"bytes,16,opt,name=str,json=Str,proto3" json:"str,omitempty"` - Bytes []byte `protobuf:"bytes,17,opt,name=bytes,json=Bytes,proto3" json:"bytes,omitempty"` - Time *timestamppb.Timestamp `protobuf:"bytes,18,opt,name=time,json=Time,proto3" json:"time,omitempty"` - Duration *durationpb.Duration `protobuf:"bytes,19,opt,name=duration,json=Duration,proto3" json:"duration,omitempty"` - Empty *EmptyStruct `protobuf:"bytes,20,opt,name=empty,json=Empty,proto3" json:"empty,omitempty"` -} - -func (x *PrimitivesStructDef) Reset() { - *x = PrimitivesStructDef{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrimitivesStructDef) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrimitivesStructDef) ProtoMessage() {} - -func (x *PrimitivesStructDef) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrimitivesStructDef.ProtoReflect.Descriptor instead. -func (*PrimitivesStructDef) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{30} -} - -func (x *PrimitivesStructDef) GetInt8() int32 { - if x != nil { - return x.Int8 - } - return 0 -} - -func (x *PrimitivesStructDef) GetInt16() int32 { - if x != nil { - return x.Int16 - } - return 0 -} - -func (x *PrimitivesStructDef) GetInt32() int32 { - if x != nil { - return x.Int32 - } - return 0 -} - -func (x *PrimitivesStructDef) GetInt32Fixed() int32 { - if x != nil { - return x.Int32Fixed - } - return 0 -} - -func (x *PrimitivesStructDef) GetInt64() int64 { - if x != nil { - return x.Int64 - } - return 0 -} - -func (x *PrimitivesStructDef) GetInt64Fixed() int64 { - if x != nil { - return x.Int64Fixed - } - return 0 -} - -func (x *PrimitivesStructDef) GetInt() int64 { - if x != nil { - return x.Int - } - return 0 -} - -func (x *PrimitivesStructDef) GetByte() uint32 { - if x != nil { - return x.Byte - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint8() uint32 { - if x != nil { - return x.Uint8 - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint16() uint32 { - if x != nil { - return x.Uint16 - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint32() uint32 { - if x != nil { - return x.Uint32 - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint32Fixed() uint32 { - if x != nil { - return x.Uint32Fixed - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint64() uint64 { - if x != nil { - return x.Uint64 - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint64Fixed() uint64 { - if x != nil { - return x.Uint64Fixed - } - return 0 -} - -func (x *PrimitivesStructDef) GetUint() uint64 { - if x != nil { - return x.Uint - } - return 0 -} - -func (x *PrimitivesStructDef) GetStr() string { - if x != nil { - return x.Str - } - return "" -} - -func (x *PrimitivesStructDef) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -func (x *PrimitivesStructDef) GetTime() *timestamppb.Timestamp { - if x != nil { - return x.Time - } - return nil -} - -func (x *PrimitivesStructDef) GetDuration() *durationpb.Duration { - if x != nil { - return x.Duration - } - return nil -} - -func (x *PrimitivesStructDef) GetEmpty() *EmptyStruct { - if x != nil { - return x.Empty - } - return nil -} - -type PrimitivesStructSl struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*PrimitivesStruct `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` -} - -func (x *PrimitivesStructSl) Reset() { - *x = PrimitivesStructSl{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrimitivesStructSl) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrimitivesStructSl) ProtoMessage() {} - -func (x *PrimitivesStructSl) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrimitivesStructSl.ProtoReflect.Descriptor instead. -func (*PrimitivesStructSl) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{31} -} - -func (x *PrimitivesStructSl) GetValue() []*PrimitivesStruct { - if x != nil { - return x.Value - } - return nil -} - -type PrimitivesStructAr struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*PrimitivesStruct `protobuf:"bytes,1,rep,name=value,proto3" json:"value,omitempty"` -} - -func (x *PrimitivesStructAr) Reset() { - *x = PrimitivesStructAr{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[32] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrimitivesStructAr) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrimitivesStructAr) ProtoMessage() {} - -func (x *PrimitivesStructAr) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[32] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrimitivesStructAr.ProtoReflect.Descriptor instead. -func (*PrimitivesStructAr) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{32} -} - -func (x *PrimitivesStructAr) GetValue() []*PrimitivesStruct { - if x != nil { - return x.Value - } - return nil -} - -type Concrete1 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *Concrete1) Reset() { - *x = Concrete1{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[33] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Concrete1) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Concrete1) ProtoMessage() {} - -func (x *Concrete1) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[33] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Concrete1.ProtoReflect.Descriptor instead. -func (*Concrete1) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{33} -} - -type Concrete2 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *Concrete2) Reset() { - *x = Concrete2{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[34] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Concrete2) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Concrete2) ProtoMessage() {} - -func (x *Concrete2) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[34] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Concrete2.ProtoReflect.Descriptor instead. -func (*Concrete2) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{34} -} - -type ConcreteTypeDef struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *ConcreteTypeDef) Reset() { - *x = ConcreteTypeDef{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[35] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ConcreteTypeDef) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ConcreteTypeDef) ProtoMessage() {} - -func (x *ConcreteTypeDef) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[35] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ConcreteTypeDef.ProtoReflect.Descriptor instead. -func (*ConcreteTypeDef) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{35} -} - -func (x *ConcreteTypeDef) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - -type ConcreteWrappedBytes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []byte `protobuf:"bytes,1,opt,name=value,json=Value,proto3" json:"value,omitempty"` -} - -func (x *ConcreteWrappedBytes) Reset() { - *x = ConcreteWrappedBytes{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[36] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ConcreteWrappedBytes) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ConcreteWrappedBytes) ProtoMessage() {} - -func (x *ConcreteWrappedBytes) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[36] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ConcreteWrappedBytes.ProtoReflect.Descriptor instead. -func (*ConcreteWrappedBytes) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{36} -} - -func (x *ConcreteWrappedBytes) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - -type InterfaceFieldsStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - F1 *anypb.Any `protobuf:"bytes,1,opt,name=f1,json=F1,proto3" json:"f1,omitempty"` - F2 *anypb.Any `protobuf:"bytes,2,opt,name=f2,json=F2,proto3" json:"f2,omitempty"` - F3 *anypb.Any `protobuf:"bytes,3,opt,name=f3,json=F3,proto3" json:"f3,omitempty"` - F4 *anypb.Any `protobuf:"bytes,4,opt,name=f4,json=F4,proto3" json:"f4,omitempty"` -} - -func (x *InterfaceFieldsStruct) Reset() { - *x = InterfaceFieldsStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[37] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InterfaceFieldsStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InterfaceFieldsStruct) ProtoMessage() {} - -func (x *InterfaceFieldsStruct) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[37] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InterfaceFieldsStruct.ProtoReflect.Descriptor instead. -func (*InterfaceFieldsStruct) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{37} -} - -func (x *InterfaceFieldsStruct) GetF1() *anypb.Any { - if x != nil { - return x.F1 - } - return nil -} - -func (x *InterfaceFieldsStruct) GetF2() *anypb.Any { - if x != nil { - return x.F2 - } - return nil -} - -func (x *InterfaceFieldsStruct) GetF3() *anypb.Any { - if x != nil { - return x.F3 - } - return nil -} - -func (x *InterfaceFieldsStruct) GetF4() *anypb.Any { - if x != nil { - return x.F4 - } - return nil -} - -type TESTS_BytesList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value [][]byte `protobuf:"bytes,1,rep,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_BytesList) Reset() { - *x = TESTS_BytesList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[38] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_BytesList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_BytesList) ProtoMessage() {} - -func (x *TESTS_BytesList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[38] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_BytesList.ProtoReflect.Descriptor instead. -func (*TESTS_BytesList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{38} -} - -func (x *TESTS_BytesList) GetValue() [][]byte { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_BytesListList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*TESTS_BytesList `protobuf:"bytes,1,rep,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_BytesListList) Reset() { - *x = TESTS_BytesListList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_BytesListList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_BytesListList) ProtoMessage() {} - -func (x *TESTS_BytesListList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[39] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_BytesListList.ProtoReflect.Descriptor instead. -func (*TESTS_BytesListList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{39} -} - -func (x *TESTS_BytesListList) GetValue() []*TESTS_BytesList { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_DurationList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*durationpb.Duration `protobuf:"bytes,1,rep,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_DurationList) Reset() { - *x = TESTS_DurationList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[40] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_DurationList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_DurationList) ProtoMessage() {} - -func (x *TESTS_DurationList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[40] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_DurationList.ProtoReflect.Descriptor instead. -func (*TESTS_DurationList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{40} -} - -func (x *TESTS_DurationList) GetValue() []*durationpb.Duration { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_EmptyStructList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*EmptyStruct `protobuf:"bytes,1,rep,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_EmptyStructList) Reset() { - *x = TESTS_EmptyStructList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[41] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_EmptyStructList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_EmptyStructList) ProtoMessage() {} - -func (x *TESTS_EmptyStructList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[41] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_EmptyStructList.ProtoReflect.Descriptor instead. -func (*TESTS_EmptyStructList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{41} -} - -func (x *TESTS_EmptyStructList) GetValue() []*EmptyStruct { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Fixed32Int32ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int32 `protobuf:"fixed32,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Fixed32Int32ValueList) Reset() { - *x = TESTS_Fixed32Int32ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[42] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Fixed32Int32ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Fixed32Int32ValueList) ProtoMessage() {} - -func (x *TESTS_Fixed32Int32ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[42] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Fixed32Int32ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_Fixed32Int32ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{42} -} - -func (x *TESTS_Fixed32Int32ValueList) GetValue() []int32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Fixed32UInt32ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []uint32 `protobuf:"fixed32,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Fixed32UInt32ValueList) Reset() { - *x = TESTS_Fixed32UInt32ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[43] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Fixed32UInt32ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Fixed32UInt32ValueList) ProtoMessage() {} - -func (x *TESTS_Fixed32UInt32ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[43] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Fixed32UInt32ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_Fixed32UInt32ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{43} -} - -func (x *TESTS_Fixed32UInt32ValueList) GetValue() []uint32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Fixed64Int64ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int64 `protobuf:"fixed64,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Fixed64Int64ValueList) Reset() { - *x = TESTS_Fixed64Int64ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[44] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Fixed64Int64ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Fixed64Int64ValueList) ProtoMessage() {} - -func (x *TESTS_Fixed64Int64ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[44] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Fixed64Int64ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_Fixed64Int64ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{44} -} - -func (x *TESTS_Fixed64Int64ValueList) GetValue() []int64 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Fixed64UInt64ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []uint64 `protobuf:"fixed64,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Fixed64UInt64ValueList) Reset() { - *x = TESTS_Fixed64UInt64ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[45] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Fixed64UInt64ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Fixed64UInt64ValueList) ProtoMessage() {} - -func (x *TESTS_Fixed64UInt64ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[45] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Fixed64UInt64ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_Fixed64UInt64ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{45} -} - -func (x *TESTS_Fixed64UInt64ValueList) GetValue() []uint64 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Int16List struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int32 `protobuf:"zigzag32,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Int16List) Reset() { - *x = TESTS_Int16List{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[46] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Int16List) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Int16List) ProtoMessage() {} - -func (x *TESTS_Int16List) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[46] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Int16List.ProtoReflect.Descriptor instead. -func (*TESTS_Int16List) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{46} -} - -func (x *TESTS_Int16List) GetValue() []int32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Int32ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int32 `protobuf:"zigzag32,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Int32ValueList) Reset() { - *x = TESTS_Int32ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[47] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Int32ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Int32ValueList) ProtoMessage() {} - -func (x *TESTS_Int32ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[47] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Int32ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_Int32ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{47} -} - -func (x *TESTS_Int32ValueList) GetValue() []int32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Int64ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int64 `protobuf:"zigzag64,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Int64ValueList) Reset() { - *x = TESTS_Int64ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[48] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Int64ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Int64ValueList) ProtoMessage() {} - -func (x *TESTS_Int64ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[48] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Int64ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_Int64ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{48} -} - -func (x *TESTS_Int64ValueList) GetValue() []int64 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_Int8List struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []int32 `protobuf:"zigzag32,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_Int8List) Reset() { - *x = TESTS_Int8List{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[49] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_Int8List) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_Int8List) ProtoMessage() {} - -func (x *TESTS_Int8List) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[49] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_Int8List.ProtoReflect.Descriptor instead. -func (*TESTS_Int8List) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{49} -} - -func (x *TESTS_Int8List) GetValue() []int32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_StringValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []string `protobuf:"bytes,1,rep,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_StringValueList) Reset() { - *x = TESTS_StringValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[50] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_StringValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_StringValueList) ProtoMessage() {} - -func (x *TESTS_StringValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[50] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_StringValueList.ProtoReflect.Descriptor instead. -func (*TESTS_StringValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{50} -} - -func (x *TESTS_StringValueList) GetValue() []string { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_TimestampList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []*timestamppb.Timestamp `protobuf:"bytes,1,rep,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_TimestampList) Reset() { - *x = TESTS_TimestampList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[51] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_TimestampList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_TimestampList) ProtoMessage() {} - -func (x *TESTS_TimestampList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[51] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_TimestampList.ProtoReflect.Descriptor instead. -func (*TESTS_TimestampList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{51} -} - -func (x *TESTS_TimestampList) GetValue() []*timestamppb.Timestamp { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_UInt16List struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []uint32 `protobuf:"varint,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_UInt16List) Reset() { - *x = TESTS_UInt16List{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[52] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_UInt16List) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_UInt16List) ProtoMessage() {} - -func (x *TESTS_UInt16List) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[52] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_UInt16List.ProtoReflect.Descriptor instead. -func (*TESTS_UInt16List) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{52} -} - -func (x *TESTS_UInt16List) GetValue() []uint32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_UInt32ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []uint32 `protobuf:"varint,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_UInt32ValueList) Reset() { - *x = TESTS_UInt32ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[53] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_UInt32ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_UInt32ValueList) ProtoMessage() {} - -func (x *TESTS_UInt32ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[53] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_UInt32ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_UInt32ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{53} -} - -func (x *TESTS_UInt32ValueList) GetValue() []uint32 { - if x != nil { - return x.Value - } - return nil -} - -type TESTS_UInt64ValueList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Value []uint64 `protobuf:"varint,1,rep,packed,name=Value,proto3" json:"Value,omitempty"` -} - -func (x *TESTS_UInt64ValueList) Reset() { - *x = TESTS_UInt64ValueList{} - if protoimpl.UnsafeEnabled { - mi := &file_tests_proto_msgTypes[54] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TESTS_UInt64ValueList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TESTS_UInt64ValueList) ProtoMessage() {} - -func (x *TESTS_UInt64ValueList) ProtoReflect() protoreflect.Message { - mi := &file_tests_proto_msgTypes[54] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TESTS_UInt64ValueList.ProtoReflect.Descriptor instead. -func (*TESTS_UInt64ValueList) Descriptor() ([]byte, []int) { - return file_tests_proto_rawDescGZIP(), []int{54} -} - -func (x *TESTS_UInt64ValueList) GetValue() []uint64 { - if x != nil { - return x.Value - } - return nil -} - -var File_tests_proto protoreflect.FileDescriptor - -var file_tests_proto_rawDesc = []byte{ - 0x0a, 0x0b, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x0d, 0x0a, 0x0b, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, - 0xc1, 0x04, 0x0a, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x74, 0x38, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x11, 0x52, 0x04, 0x49, 0x6e, 0x74, 0x38, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x31, - 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x12, 0x14, - 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, - 0x78, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0f, 0x52, 0x0a, 0x49, 0x6e, 0x74, 0x33, 0x32, - 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x12, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x12, 0x1f, 0x0a, 0x0b, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x10, - 0x52, 0x0a, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, - 0x69, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x12, 0x52, 0x03, 0x49, 0x6e, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x62, 0x79, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x42, 0x79, - 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x05, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x69, 0x6e, 0x74, - 0x31, 0x36, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x31, 0x36, - 0x12, 0x16, 0x0a, 0x06, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, - 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x07, 0x52, 0x0b, - 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x55, 0x69, 0x6e, - 0x74, 0x36, 0x34, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, - 0x78, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0b, 0x55, 0x69, 0x6e, 0x74, 0x36, - 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x69, 0x6e, 0x74, 0x18, 0x0f, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x55, 0x69, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, - 0x72, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x53, 0x74, 0x72, 0x12, 0x14, 0x0a, 0x05, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x54, 0x69, - 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x6d, 0x70, - 0x74, 0x79, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x84, 0x01, 0x0a, 0x11, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x41, 0x72, 0x72, - 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, 0x6d, - 0x65, 0x5f, 0x61, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x54, 0x69, 0x6d, 0x65, 0x41, 0x72, 0x12, 0x3a, - 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, - 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x22, 0xa1, 0x05, 0x0a, 0x0c, 0x41, - 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x69, - 0x6e, 0x74, 0x38, 0x5f, 0x61, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x11, 0x52, 0x06, 0x49, 0x6e, - 0x74, 0x38, 0x41, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x61, 0x72, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x11, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x41, 0x72, 0x12, - 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x61, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x11, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x6e, - 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0f, 0x52, 0x0c, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, 0x72, - 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x61, 0x72, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x12, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x41, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x10, 0x52, 0x0c, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, - 0x72, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x72, 0x18, 0x07, 0x20, 0x03, 0x28, - 0x12, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x41, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x79, 0x74, 0x65, - 0x5f, 0x61, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x42, 0x79, 0x74, 0x65, 0x41, - 0x72, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x61, 0x72, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x41, 0x72, 0x12, 0x1b, 0x0a, 0x09, - 0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x61, 0x72, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0d, 0x52, - 0x08, 0x55, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x41, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x69, 0x6e, - 0x74, 0x33, 0x32, 0x5f, 0x61, 0x72, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x55, 0x69, - 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, - 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x07, 0x52, - 0x0d, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, 0x72, 0x12, 0x1b, - 0x0a, 0x09, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x61, 0x72, 0x18, 0x0d, 0x20, 0x03, 0x28, - 0x04, 0x52, 0x08, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x41, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x75, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x18, 0x0e, - 0x20, 0x03, 0x28, 0x06, 0x52, 0x0d, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, - 0x64, 0x41, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x72, 0x18, 0x0f, - 0x20, 0x03, 0x28, 0x04, 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x41, 0x72, 0x12, 0x15, 0x0a, 0x06, - 0x73, 0x74, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x53, 0x74, - 0x72, 0x41, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x61, 0x72, 0x18, - 0x11, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x07, 0x42, 0x79, 0x74, 0x65, 0x73, 0x41, 0x72, 0x12, 0x33, - 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x61, 0x72, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x54, 0x69, 0x6d, - 0x65, 0x41, 0x72, 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x61, 0x72, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x12, - 0x2d, 0x0a, 0x08, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x61, 0x72, 0x18, 0x14, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x07, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x41, 0x72, 0x22, 0xd6, - 0x09, 0x0a, 0x12, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x61, 0x72, - 0x5f, 0x61, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x38, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x08, 0x49, 0x6e, 0x74, 0x38, 0x41, 0x72, 0x41, 0x72, 0x12, 0x36, 0x0a, 0x0b, 0x69, 0x6e, - 0x74, 0x31, 0x36, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, - 0x74, 0x31, 0x36, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x41, 0x72, - 0x41, 0x72, 0x12, 0x3b, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x61, 0x72, 0x5f, 0x61, - 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x41, 0x72, 0x12, - 0x4d, 0x0a, 0x11, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, - 0x72, 0x5f, 0x61, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, 0x72, 0x41, 0x72, 0x12, 0x3b, - 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, - 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x09, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x41, 0x72, 0x41, 0x72, 0x12, 0x4d, 0x0a, 0x11, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, - 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, 0x72, 0x41, 0x72, 0x12, 0x37, 0x0a, 0x09, 0x69, 0x6e, - 0x74, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x41, - 0x72, 0x41, 0x72, 0x12, 0x1c, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x61, 0x72, 0x5f, 0x61, - 0x72, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x42, 0x79, 0x74, 0x65, 0x41, 0x72, 0x41, - 0x72, 0x12, 0x1e, 0x0a, 0x0b, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, - 0x18, 0x09, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x41, 0x72, 0x41, - 0x72, 0x12, 0x39, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x61, 0x72, 0x5f, 0x61, - 0x72, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x41, 0x72, 0x41, 0x72, 0x12, 0x3e, 0x0a, 0x0c, - 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x0b, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, - 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x41, 0x72, 0x41, 0x72, 0x12, 0x50, 0x0a, 0x12, - 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, 0x72, 0x5f, - 0x61, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, - 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x55, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0f, 0x55, - 0x69, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, 0x72, 0x41, 0x72, 0x12, 0x3e, - 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x0d, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, - 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x41, 0x72, 0x41, 0x72, 0x12, 0x50, - 0x0a, 0x12, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x61, - 0x72, 0x5f, 0x61, 0x72, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, - 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x0f, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x41, 0x72, 0x41, 0x72, - 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x0f, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, - 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x08, 0x55, 0x69, 0x6e, 0x74, 0x41, 0x72, 0x41, 0x72, 0x12, 0x38, 0x0a, 0x09, - 0x73, 0x74, 0x72, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x53, - 0x74, 0x72, 0x41, 0x72, 0x41, 0x72, 0x12, 0x36, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, - 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x65, - 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x09, 0x42, 0x79, 0x74, 0x65, 0x73, 0x41, 0x72, 0x41, 0x72, 0x12, 0x38, - 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x12, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, - 0x5f, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, - 0x54, 0x69, 0x6d, 0x65, 0x41, 0x72, 0x41, 0x72, 0x12, 0x3f, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x44, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0c, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x41, 0x72, 0x12, 0x3c, 0x0a, 0x0b, 0x65, 0x6d, 0x70, - 0x74, 0x79, 0x5f, 0x61, 0x72, 0x5f, 0x61, 0x72, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x09, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x41, 0x72, 0x41, 0x72, 0x22, 0xa1, 0x05, 0x0a, 0x0c, 0x53, 0x6c, 0x69, 0x63, - 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x6e, 0x74, 0x38, - 0x5f, 0x73, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x11, 0x52, 0x06, 0x49, 0x6e, 0x74, 0x38, 0x53, - 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x73, 0x6c, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x11, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x53, 0x6c, 0x12, 0x19, 0x0a, 0x08, - 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x73, 0x6c, 0x18, 0x03, 0x20, 0x03, 0x28, 0x11, 0x52, 0x07, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x53, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x33, 0x32, - 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0f, 0x52, - 0x0c, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, 0x12, 0x19, 0x0a, - 0x08, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x73, 0x6c, 0x18, 0x05, 0x20, 0x03, 0x28, 0x12, 0x52, - 0x07, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x53, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x36, - 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x18, 0x06, 0x20, 0x03, 0x28, 0x10, - 0x52, 0x0c, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, 0x12, 0x15, - 0x0a, 0x06, 0x69, 0x6e, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x12, 0x52, 0x05, - 0x49, 0x6e, 0x74, 0x53, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x73, 0x6c, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x42, 0x79, 0x74, 0x65, 0x53, 0x6c, 0x12, 0x19, - 0x0a, 0x08, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x73, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x07, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x53, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x69, 0x6e, - 0x74, 0x31, 0x36, 0x5f, 0x73, 0x6c, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x55, 0x69, - 0x6e, 0x74, 0x31, 0x36, 0x53, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, - 0x5f, 0x73, 0x6c, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x55, 0x69, 0x6e, 0x74, 0x33, - 0x32, 0x53, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, - 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x07, 0x52, 0x0d, 0x55, 0x69, - 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x75, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x73, 0x6c, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x04, 0x52, 0x08, - 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x53, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x75, 0x69, 0x6e, 0x74, - 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x18, 0x0e, 0x20, 0x03, 0x28, - 0x06, 0x52, 0x0d, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, - 0x12, 0x17, 0x0a, 0x07, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x0f, 0x20, 0x03, 0x28, - 0x04, 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x53, 0x6c, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x74, 0x72, - 0x5f, 0x73, 0x6c, 0x18, 0x10, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x53, 0x74, 0x72, 0x53, 0x6c, - 0x12, 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x6c, 0x18, 0x11, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x07, 0x42, 0x79, 0x74, 0x65, 0x73, 0x53, 0x6c, 0x12, 0x33, 0x0a, 0x07, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x6c, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x6c, - 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6c, 0x18, - 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0a, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6c, 0x12, 0x2d, 0x0a, 0x08, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x73, 0x6c, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x52, 0x07, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x6c, 0x22, 0xd6, 0x09, 0x0a, 0x12, - 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, - 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x38, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x49, - 0x6e, 0x74, 0x38, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x36, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x31, 0x36, - 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x31, 0x36, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x53, 0x6c, 0x53, 0x6c, 0x12, - 0x3b, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, - 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x4d, 0x0a, 0x11, - 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x5f, 0x73, - 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x49, 0x6e, 0x74, - 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x49, 0x6e, 0x74, - 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x3b, 0x0a, 0x0b, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x09, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x4d, 0x0a, 0x11, 0x69, 0x6e, 0x74, 0x36, - 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, - 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, - 0x78, 0x65, 0x64, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x37, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x73, - 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x53, 0x6c, 0x53, 0x6c, - 0x12, 0x1c, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x08, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x42, 0x79, 0x74, 0x65, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x1e, - 0x0a, 0x0b, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x09, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x09, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x39, - 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x0a, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, - 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0a, 0x55, - 0x69, 0x6e, 0x74, 0x31, 0x36, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x3e, 0x0a, 0x0c, 0x75, 0x69, 0x6e, - 0x74, 0x33, 0x32, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x55, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0a, 0x55, - 0x69, 0x6e, 0x74, 0x33, 0x32, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x50, 0x0a, 0x12, 0x75, 0x69, 0x6e, - 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, - 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, - 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x55, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0f, 0x55, 0x69, 0x6e, 0x74, - 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x3e, 0x0a, 0x0c, 0x75, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x0d, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, - 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x50, 0x0a, 0x12, 0x75, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x5f, 0x73, - 0x6c, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x55, 0x49, 0x6e, - 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0f, 0x55, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x3a, 0x0a, - 0x0a, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x0f, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, - 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x08, 0x55, 0x69, 0x6e, 0x74, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x74, 0x72, - 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x53, 0x74, 0x72, 0x53, - 0x6c, 0x53, 0x6c, 0x12, 0x36, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x6c, 0x5f, - 0x73, 0x6c, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, - 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x09, 0x42, 0x79, 0x74, 0x65, 0x73, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x38, 0x0a, 0x0a, 0x74, - 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x3f, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x44, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0c, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x6c, 0x53, 0x6c, 0x12, 0x3c, 0x0a, 0x0b, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, - 0x73, 0x6c, 0x5f, 0x73, 0x6c, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, - 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x09, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x53, 0x6c, 0x53, 0x6c, 0x22, 0xa3, 0x05, 0x0a, 0x0e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x6e, 0x74, 0x38, 0x5f, - 0x70, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11, 0x52, 0x06, 0x49, 0x6e, 0x74, 0x38, 0x50, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x11, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x50, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, - 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x70, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x11, 0x52, 0x07, 0x49, - 0x6e, 0x74, 0x33, 0x32, 0x50, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, - 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0f, 0x52, 0x0c, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x12, 0x19, 0x0a, 0x08, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x70, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x12, 0x52, 0x07, - 0x49, 0x6e, 0x74, 0x36, 0x34, 0x50, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x36, 0x34, - 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x10, 0x52, - 0x0c, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x12, 0x15, 0x0a, - 0x06, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x12, 0x52, 0x05, 0x49, - 0x6e, 0x74, 0x50, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x70, 0x74, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x42, 0x79, 0x74, 0x65, 0x50, 0x74, 0x12, 0x19, 0x0a, - 0x08, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x70, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x07, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x50, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x69, 0x6e, 0x74, - 0x31, 0x36, 0x5f, 0x70, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x55, 0x69, 0x6e, - 0x74, 0x31, 0x36, 0x50, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, - 0x70, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, - 0x50, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, - 0x65, 0x64, 0x5f, 0x70, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x07, 0x52, 0x0d, 0x55, 0x69, 0x6e, - 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x70, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x55, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x50, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x75, 0x69, 0x6e, 0x74, 0x36, - 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x06, - 0x52, 0x0d, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x12, - 0x17, 0x0a, 0x07, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x50, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x5f, - 0x70, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x53, 0x74, 0x72, 0x50, 0x74, 0x12, - 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x74, 0x12, 0x33, 0x0a, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x70, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x54, 0x69, 0x6d, 0x65, 0x50, 0x74, 0x12, - 0x3a, 0x0a, 0x0b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x74, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0a, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x65, - 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x70, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x52, 0x07, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x50, 0x74, 0x22, 0x8c, 0x06, 0x0a, 0x13, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x11, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x38, 0x50, 0x74, 0x53, 0x6c, - 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x11, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x50, 0x74, 0x53, 0x6c, - 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x11, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x50, 0x74, 0x53, 0x6c, - 0x12, 0x29, 0x0a, 0x11, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, - 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0f, 0x52, 0x0e, 0x49, 0x6e, 0x74, - 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x1e, 0x0a, 0x0b, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x05, 0x20, 0x03, 0x28, 0x12, - 0x52, 0x09, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x29, 0x0a, 0x11, 0x69, - 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x10, 0x52, 0x0e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, - 0x65, 0x64, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x1a, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x74, - 0x5f, 0x73, 0x6c, 0x18, 0x07, 0x20, 0x03, 0x28, 0x12, 0x52, 0x07, 0x49, 0x6e, 0x74, 0x50, 0x74, - 0x53, 0x6c, 0x12, 0x1c, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x42, 0x79, 0x74, 0x65, 0x50, 0x74, 0x53, 0x6c, - 0x12, 0x1e, 0x0a, 0x0b, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x55, 0x69, 0x6e, 0x74, 0x38, 0x50, 0x74, 0x53, 0x6c, - 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, - 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x50, 0x74, - 0x53, 0x6c, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x70, 0x74, 0x5f, - 0x73, 0x6c, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, - 0x50, 0x74, 0x53, 0x6c, 0x12, 0x2b, 0x0a, 0x12, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, - 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x07, - 0x52, 0x0f, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x53, - 0x6c, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x70, 0x74, 0x5f, 0x73, - 0x6c, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0a, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x50, - 0x74, 0x53, 0x6c, 0x12, 0x2b, 0x0a, 0x12, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, - 0x78, 0x65, 0x64, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x06, 0x52, - 0x0f, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x74, 0x53, 0x6c, - 0x12, 0x1c, 0x0a, 0x0a, 0x75, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x0f, - 0x20, 0x03, 0x28, 0x04, 0x52, 0x08, 0x55, 0x69, 0x6e, 0x74, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x1a, - 0x0a, 0x09, 0x73, 0x74, 0x72, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x10, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x07, 0x53, 0x74, 0x72, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x1e, 0x0a, 0x0b, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x09, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x38, 0x0a, 0x0a, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x54, 0x69, 0x6d, 0x65, - 0x50, 0x74, 0x53, 0x6c, 0x12, 0x3f, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x70, 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x50, 0x74, 0x53, 0x6c, 0x12, 0x32, 0x0a, 0x0b, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x70, - 0x74, 0x5f, 0x73, 0x6c, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x50, 0x74, 0x53, 0x6c, 0x22, 0xd1, 0x01, 0x0a, 0x09, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x74, 0x12, 0x32, 0x0a, 0x08, 0x70, 0x72, 0x5f, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x52, 0x07, 0x50, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2e, 0x0a, 0x08, 0x61, - 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x52, 0x07, 0x41, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2e, 0x0a, 0x08, 0x73, - 0x6c, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x52, 0x07, 0x53, 0x6c, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x30, 0x0a, 0x08, 0x70, - 0x74, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x07, 0x50, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x53, 0x0a, - 0x0b, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x74, 0x31, 0x12, 0x44, 0x0a, 0x11, - 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x22, 0x87, 0x02, 0x0a, 0x0b, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, - 0x74, 0x32, 0x12, 0x44, 0x0a, 0x11, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, - 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x38, 0x0a, 0x0d, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x0c, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x12, 0x38, 0x0a, 0x0d, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x5f, 0x73, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x73, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0c, - 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x3e, 0x0a, 0x0f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0e, 0x50, 0x6f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0xbe, 0x02, 0x0a, - 0x0b, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x74, 0x33, 0x12, 0x44, 0x0a, 0x11, - 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x12, 0x38, 0x0a, 0x0d, 0x61, 0x72, 0x72, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x73, 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0c, - 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x38, 0x0a, 0x0d, - 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x69, 0x63, - 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0c, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x35, 0x0a, 0x0c, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, - 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x0b, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x81, 0x03, - 0x0a, 0x0b, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x74, 0x34, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x6f, 0x6f, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x12, 0x52, 0x04, 0x46, 0x6f, 0x6f, - 0x31, 0x12, 0x44, 0x0a, 0x11, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x5f, - 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, - 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6f, 0x6f, 0x32, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6f, 0x6f, 0x32, 0x12, 0x43, 0x0a, 0x13, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, - 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x11, 0x41, - 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6f, 0x6f, 0x33, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x46, 0x6f, 0x6f, 0x33, 0x12, 0x38, 0x0a, 0x0d, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x5f, 0x73, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, - 0x73, 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x0c, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x66, 0x6f, 0x6f, 0x34, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x46, 0x6f, - 0x6f, 0x34, 0x12, 0x49, 0x0a, 0x15, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x73, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x13, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x6f, 0x6f, 0x35, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x46, 0x6f, 0x6f, - 0x35, 0x22, 0x8d, 0x03, 0x0a, 0x17, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x74, - 0x35, 0x4e, 0x61, 0x6d, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x6f, 0x6f, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x12, 0x52, 0x04, 0x46, 0x6f, 0x6f, - 0x31, 0x12, 0x44, 0x0a, 0x11, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x5f, - 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, - 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6f, 0x6f, 0x32, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6f, 0x6f, 0x32, 0x12, 0x43, 0x0a, 0x13, 0x61, - 0x72, 0x72, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, - 0x2e, 0x41, 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x11, 0x41, - 0x72, 0x72, 0x61, 0x79, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6f, 0x6f, 0x33, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x46, 0x6f, 0x6f, 0x33, 0x12, 0x38, 0x0a, 0x0d, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x5f, 0x73, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x65, - 0x73, 0x74, 0x73, 0x2e, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x0c, 0x53, 0x6c, 0x69, 0x63, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x66, 0x6f, 0x6f, 0x34, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x46, 0x6f, - 0x6f, 0x34, 0x12, 0x49, 0x0a, 0x15, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x5f, 0x73, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x13, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x6f, 0x6f, 0x35, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x46, 0x6f, 0x6f, - 0x35, 0x22, 0x33, 0x0a, 0x15, 0x41, 0x6d, 0x69, 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, - 0x6c, 0x65, 0x72, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x31, 0x12, 0x0c, 0x0a, 0x01, 0x63, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x12, 0x52, 0x01, 0x43, 0x12, 0x0c, 0x0a, 0x01, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x12, 0x52, 0x01, 0x44, 0x22, 0x29, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x72, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x31, 0x12, 0x0c, 0x0a, 0x01, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x12, - 0x52, 0x01, 0x43, 0x12, 0x0c, 0x0a, 0x01, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x12, 0x52, 0x01, - 0x44, 0x22, 0x3f, 0x0a, 0x15, 0x41, 0x6d, 0x69, 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, - 0x6c, 0x65, 0x72, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x32, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x73, 0x2e, 0x52, 0x65, 0x70, 0x72, 0x45, 0x6c, 0x65, 0x6d, 0x32, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x22, 0x49, 0x0a, 0x09, 0x52, 0x65, 0x70, 0x72, 0x45, 0x6c, 0x65, 0x6d, 0x32, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4b, 0x65, - 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2d, 0x0a, - 0x15, 0x41, 0x6d, 0x69, 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x65, 0x72, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x33, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x22, 0x0a, 0x12, - 0x41, 0x6d, 0x69, 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x65, 0x72, 0x49, 0x6e, - 0x74, 0x34, 0x12, 0x0c, 0x0a, 0x01, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11, 0x52, 0x01, 0x41, - 0x22, 0x2a, 0x0a, 0x12, 0x41, 0x6d, 0x69, 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, - 0x65, 0x72, 0x49, 0x6e, 0x74, 0x35, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4b, 0x0a, 0x15, - 0x41, 0x6d, 0x69, 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x36, 0x12, 0x32, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x41, 0x6d, 0x69, - 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x31, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2d, 0x0a, 0x15, 0x41, 0x6d, 0x69, - 0x6e, 0x6f, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x37, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x21, 0x0a, 0x09, 0x52, 0x65, 0x70, 0x72, - 0x45, 0x6c, 0x65, 0x6d, 0x37, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x06, 0x49, - 0x6e, 0x74, 0x44, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x12, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1d, 0x0a, 0x05, 0x49, - 0x6e, 0x74, 0x41, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x12, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1d, 0x0a, 0x05, 0x49, 0x6e, - 0x74, 0x53, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x12, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x06, 0x42, 0x79, 0x74, - 0x65, 0x41, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x06, 0x42, 0x79, 0x74, - 0x65, 0x53, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xc4, 0x04, 0x0a, 0x13, 0x50, 0x72, - 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x44, 0x65, - 0x66, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x74, 0x38, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11, 0x52, - 0x04, 0x49, 0x6e, 0x74, 0x38, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x12, 0x14, 0x0a, 0x05, 0x69, - 0x6e, 0x74, 0x33, 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0f, 0x52, 0x0a, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, - 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x12, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x36, - 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x10, 0x52, 0x0a, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x6e, 0x74, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x12, 0x52, 0x03, 0x49, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x62, - 0x79, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x42, 0x79, 0x74, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, - 0x55, 0x69, 0x6e, 0x74, 0x38, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x18, - 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x12, 0x16, 0x0a, - 0x06, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x55, - 0x69, 0x6e, 0x74, 0x33, 0x32, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x5f, - 0x66, 0x69, 0x78, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x07, 0x52, 0x0b, 0x55, 0x69, 0x6e, - 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x69, 0x6e, 0x74, - 0x36, 0x34, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, - 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, - 0x18, 0x0e, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0b, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x46, 0x69, - 0x78, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x69, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x04, 0x55, 0x69, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x74, 0x72, 0x18, 0x10, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x53, 0x74, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, - 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x18, - 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x22, 0x43, 0x0a, 0x12, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x53, 0x6c, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x72, - 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x43, 0x0a, 0x12, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, - 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x41, 0x72, 0x12, 0x2d, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x0b, 0x0a, 0x09, 0x43, 0x6f, - 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x31, 0x22, 0x0b, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x63, 0x72, - 0x65, 0x74, 0x65, 0x32, 0x22, 0x27, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x44, 0x65, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, - 0x14, 0x43, 0x6f, 0x6e, 0x63, 0x72, 0x65, 0x74, 0x65, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, - 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xaf, 0x01, 0x0a, 0x15, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x24, 0x0a, 0x02, 0x66, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x02, 0x46, 0x31, 0x12, 0x24, 0x0a, 0x02, 0x66, - 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x02, 0x46, - 0x32, 0x12, 0x24, 0x0a, 0x02, 0x66, 0x33, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x41, 0x6e, 0x79, 0x52, 0x02, 0x46, 0x33, 0x12, 0x24, 0x0a, 0x02, 0x66, 0x34, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x02, 0x46, 0x34, 0x22, 0x27, 0x0a, - 0x0f, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, - 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x43, 0x0a, 0x13, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, - 0x42, 0x79, 0x74, 0x65, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2c, 0x0a, - 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x45, 0x0a, 0x12, 0x54, - 0x45, 0x53, 0x54, 0x53, 0x5f, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x2f, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x22, 0x41, 0x0a, 0x15, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x05, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x33, 0x0a, 0x1b, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, - 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0f, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x34, 0x0a, 0x1c, 0x54, 0x45, - 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x55, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x07, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x22, 0x33, 0x0a, 0x1b, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x36, - 0x34, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x10, 0x52, 0x05, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x34, 0x0a, 0x1c, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x46, - 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x06, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x27, 0x0a, 0x0f, 0x54, - 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x31, 0x36, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, - 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x11, 0x52, 0x05, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x14, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, - 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x11, 0x52, 0x05, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x22, 0x2c, 0x0a, 0x14, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x12, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x22, 0x26, 0x0a, 0x0e, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x49, 0x6e, 0x74, 0x38, 0x4c, 0x69, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x11, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2d, 0x0a, 0x15, 0x54, 0x45, 0x53, 0x54, - 0x53, 0x5f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x47, 0x0a, 0x13, 0x54, 0x45, 0x53, 0x54, 0x53, - 0x5f, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, - 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x22, 0x28, 0x0a, 0x10, 0x54, 0x45, 0x53, 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x31, 0x36, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0d, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2d, 0x0a, 0x15, 0x54, 0x45, - 0x53, 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, - 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0d, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x2d, 0x0a, 0x15, 0x54, 0x45, 0x53, - 0x54, 0x53, 0x5f, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x04, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6e, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x67, - 0x6e, 0x6f, 0x2f, 0x74, 0x6d, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, - 0x2f, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var ( - file_tests_proto_rawDescOnce sync.Once - file_tests_proto_rawDescData = file_tests_proto_rawDesc -) - -func file_tests_proto_rawDescGZIP() []byte { - file_tests_proto_rawDescOnce.Do(func() { - file_tests_proto_rawDescData = protoimpl.X.CompressGZIP(file_tests_proto_rawDescData) - }) - return file_tests_proto_rawDescData -} - -var file_tests_proto_msgTypes = make([]protoimpl.MessageInfo, 55) -var file_tests_proto_goTypes = []interface{}{ - (*EmptyStruct)(nil), // 0: tests.EmptyStruct - (*PrimitivesStruct)(nil), // 1: tests.PrimitivesStruct - (*ShortArraysStruct)(nil), // 2: tests.ShortArraysStruct - (*ArraysStruct)(nil), // 3: tests.ArraysStruct - (*ArraysArraysStruct)(nil), // 4: tests.ArraysArraysStruct - (*SlicesStruct)(nil), // 5: tests.SlicesStruct - (*SlicesSlicesStruct)(nil), // 6: tests.SlicesSlicesStruct - (*PointersStruct)(nil), // 7: tests.PointersStruct - (*PointerSlicesStruct)(nil), // 8: tests.PointerSlicesStruct - (*ComplexSt)(nil), // 9: tests.ComplexSt - (*EmbeddedSt1)(nil), // 10: tests.EmbeddedSt1 - (*EmbeddedSt2)(nil), // 11: tests.EmbeddedSt2 - (*EmbeddedSt3)(nil), // 12: tests.EmbeddedSt3 - (*EmbeddedSt4)(nil), // 13: tests.EmbeddedSt4 - (*EmbeddedSt5NameOverride)(nil), // 14: tests.EmbeddedSt5NameOverride - (*AminoMarshalerStruct1)(nil), // 15: tests.AminoMarshalerStruct1 - (*ReprStruct1)(nil), // 16: tests.ReprStruct1 - (*AminoMarshalerStruct2)(nil), // 17: tests.AminoMarshalerStruct2 - (*ReprElem2)(nil), // 18: tests.ReprElem2 - (*AminoMarshalerStruct3)(nil), // 19: tests.AminoMarshalerStruct3 - (*AminoMarshalerInt4)(nil), // 20: tests.AminoMarshalerInt4 - (*AminoMarshalerInt5)(nil), // 21: tests.AminoMarshalerInt5 - (*AminoMarshalerStruct6)(nil), // 22: tests.AminoMarshalerStruct6 - (*AminoMarshalerStruct7)(nil), // 23: tests.AminoMarshalerStruct7 - (*ReprElem7)(nil), // 24: tests.ReprElem7 - (*IntDef)(nil), // 25: tests.IntDef - (*IntAr)(nil), // 26: tests.IntAr - (*IntSl)(nil), // 27: tests.IntSl - (*ByteAr)(nil), // 28: tests.ByteAr - (*ByteSl)(nil), // 29: tests.ByteSl - (*PrimitivesStructDef)(nil), // 30: tests.PrimitivesStructDef - (*PrimitivesStructSl)(nil), // 31: tests.PrimitivesStructSl - (*PrimitivesStructAr)(nil), // 32: tests.PrimitivesStructAr - (*Concrete1)(nil), // 33: tests.Concrete1 - (*Concrete2)(nil), // 34: tests.Concrete2 - (*ConcreteTypeDef)(nil), // 35: tests.ConcreteTypeDef - (*ConcreteWrappedBytes)(nil), // 36: tests.ConcreteWrappedBytes - (*InterfaceFieldsStruct)(nil), // 37: tests.InterfaceFieldsStruct - (*TESTS_BytesList)(nil), // 38: tests.TESTS_BytesList - (*TESTS_BytesListList)(nil), // 39: tests.TESTS_BytesListList - (*TESTS_DurationList)(nil), // 40: tests.TESTS_DurationList - (*TESTS_EmptyStructList)(nil), // 41: tests.TESTS_EmptyStructList - (*TESTS_Fixed32Int32ValueList)(nil), // 42: tests.TESTS_Fixed32Int32ValueList - (*TESTS_Fixed32UInt32ValueList)(nil), // 43: tests.TESTS_Fixed32UInt32ValueList - (*TESTS_Fixed64Int64ValueList)(nil), // 44: tests.TESTS_Fixed64Int64ValueList - (*TESTS_Fixed64UInt64ValueList)(nil), // 45: tests.TESTS_Fixed64UInt64ValueList - (*TESTS_Int16List)(nil), // 46: tests.TESTS_Int16List - (*TESTS_Int32ValueList)(nil), // 47: tests.TESTS_Int32ValueList - (*TESTS_Int64ValueList)(nil), // 48: tests.TESTS_Int64ValueList - (*TESTS_Int8List)(nil), // 49: tests.TESTS_Int8List - (*TESTS_StringValueList)(nil), // 50: tests.TESTS_StringValueList - (*TESTS_TimestampList)(nil), // 51: tests.TESTS_TimestampList - (*TESTS_UInt16List)(nil), // 52: tests.TESTS_UInt16List - (*TESTS_UInt32ValueList)(nil), // 53: tests.TESTS_UInt32ValueList - (*TESTS_UInt64ValueList)(nil), // 54: tests.TESTS_UInt64ValueList - (*timestamppb.Timestamp)(nil), // 55: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 56: google.protobuf.Duration - (*anypb.Any)(nil), // 57: google.protobuf.Any -} -var file_tests_proto_depIdxs = []int32{ - 55, // 0: tests.PrimitivesStruct.time:type_name -> google.protobuf.Timestamp - 56, // 1: tests.PrimitivesStruct.duration:type_name -> google.protobuf.Duration - 0, // 2: tests.PrimitivesStruct.empty:type_name -> tests.EmptyStruct - 55, // 3: tests.ShortArraysStruct.time_ar:type_name -> google.protobuf.Timestamp - 56, // 4: tests.ShortArraysStruct.duration_ar:type_name -> google.protobuf.Duration - 55, // 5: tests.ArraysStruct.time_ar:type_name -> google.protobuf.Timestamp - 56, // 6: tests.ArraysStruct.duration_ar:type_name -> google.protobuf.Duration - 0, // 7: tests.ArraysStruct.empty_ar:type_name -> tests.EmptyStruct - 49, // 8: tests.ArraysArraysStruct.int8_ar_ar:type_name -> tests.TESTS_Int8List - 46, // 9: tests.ArraysArraysStruct.int16_ar_ar:type_name -> tests.TESTS_Int16List - 47, // 10: tests.ArraysArraysStruct.int32_ar_ar:type_name -> tests.TESTS_Int32ValueList - 42, // 11: tests.ArraysArraysStruct.int32_fixed_ar_ar:type_name -> tests.TESTS_Fixed32Int32ValueList - 48, // 12: tests.ArraysArraysStruct.int64_ar_ar:type_name -> tests.TESTS_Int64ValueList - 44, // 13: tests.ArraysArraysStruct.int64_fixed_ar_ar:type_name -> tests.TESTS_Fixed64Int64ValueList - 48, // 14: tests.ArraysArraysStruct.int_ar_ar:type_name -> tests.TESTS_Int64ValueList - 52, // 15: tests.ArraysArraysStruct.uint16_ar_ar:type_name -> tests.TESTS_UInt16List - 53, // 16: tests.ArraysArraysStruct.uint32_ar_ar:type_name -> tests.TESTS_UInt32ValueList - 43, // 17: tests.ArraysArraysStruct.uint32_fixed_ar_ar:type_name -> tests.TESTS_Fixed32UInt32ValueList - 54, // 18: tests.ArraysArraysStruct.uint64_ar_ar:type_name -> tests.TESTS_UInt64ValueList - 45, // 19: tests.ArraysArraysStruct.uint64_fixed_ar_ar:type_name -> tests.TESTS_Fixed64UInt64ValueList - 54, // 20: tests.ArraysArraysStruct.uint_ar_ar:type_name -> tests.TESTS_UInt64ValueList - 50, // 21: tests.ArraysArraysStruct.str_ar_ar:type_name -> tests.TESTS_StringValueList - 38, // 22: tests.ArraysArraysStruct.bytes_ar_ar:type_name -> tests.TESTS_BytesList - 51, // 23: tests.ArraysArraysStruct.time_ar_ar:type_name -> tests.TESTS_TimestampList - 40, // 24: tests.ArraysArraysStruct.duration_ar_ar:type_name -> tests.TESTS_DurationList - 41, // 25: tests.ArraysArraysStruct.empty_ar_ar:type_name -> tests.TESTS_EmptyStructList - 55, // 26: tests.SlicesStruct.time_sl:type_name -> google.protobuf.Timestamp - 56, // 27: tests.SlicesStruct.duration_sl:type_name -> google.protobuf.Duration - 0, // 28: tests.SlicesStruct.empty_sl:type_name -> tests.EmptyStruct - 49, // 29: tests.SlicesSlicesStruct.int8_sl_sl:type_name -> tests.TESTS_Int8List - 46, // 30: tests.SlicesSlicesStruct.int16_sl_sl:type_name -> tests.TESTS_Int16List - 47, // 31: tests.SlicesSlicesStruct.int32_sl_sl:type_name -> tests.TESTS_Int32ValueList - 42, // 32: tests.SlicesSlicesStruct.int32_fixed_sl_sl:type_name -> tests.TESTS_Fixed32Int32ValueList - 48, // 33: tests.SlicesSlicesStruct.int64_sl_sl:type_name -> tests.TESTS_Int64ValueList - 44, // 34: tests.SlicesSlicesStruct.int64_fixed_sl_sl:type_name -> tests.TESTS_Fixed64Int64ValueList - 48, // 35: tests.SlicesSlicesStruct.int_sl_sl:type_name -> tests.TESTS_Int64ValueList - 52, // 36: tests.SlicesSlicesStruct.uint16_sl_sl:type_name -> tests.TESTS_UInt16List - 53, // 37: tests.SlicesSlicesStruct.uint32_sl_sl:type_name -> tests.TESTS_UInt32ValueList - 43, // 38: tests.SlicesSlicesStruct.uint32_fixed_sl_sl:type_name -> tests.TESTS_Fixed32UInt32ValueList - 54, // 39: tests.SlicesSlicesStruct.uint64_sl_sl:type_name -> tests.TESTS_UInt64ValueList - 45, // 40: tests.SlicesSlicesStruct.uint64_fixed_sl_sl:type_name -> tests.TESTS_Fixed64UInt64ValueList - 54, // 41: tests.SlicesSlicesStruct.uint_sl_sl:type_name -> tests.TESTS_UInt64ValueList - 50, // 42: tests.SlicesSlicesStruct.str_sl_sl:type_name -> tests.TESTS_StringValueList - 38, // 43: tests.SlicesSlicesStruct.bytes_sl_sl:type_name -> tests.TESTS_BytesList - 51, // 44: tests.SlicesSlicesStruct.time_sl_sl:type_name -> tests.TESTS_TimestampList - 40, // 45: tests.SlicesSlicesStruct.duration_sl_sl:type_name -> tests.TESTS_DurationList - 41, // 46: tests.SlicesSlicesStruct.empty_sl_sl:type_name -> tests.TESTS_EmptyStructList - 55, // 47: tests.PointersStruct.time_pt:type_name -> google.protobuf.Timestamp - 56, // 48: tests.PointersStruct.duration_pt:type_name -> google.protobuf.Duration - 0, // 49: tests.PointersStruct.empty_pt:type_name -> tests.EmptyStruct - 55, // 50: tests.PointerSlicesStruct.time_pt_sl:type_name -> google.protobuf.Timestamp - 56, // 51: tests.PointerSlicesStruct.duration_pt_sl:type_name -> google.protobuf.Duration - 0, // 52: tests.PointerSlicesStruct.empty_pt_sl:type_name -> tests.EmptyStruct - 1, // 53: tests.ComplexSt.pr_field:type_name -> tests.PrimitivesStruct - 3, // 54: tests.ComplexSt.ar_field:type_name -> tests.ArraysStruct - 5, // 55: tests.ComplexSt.sl_field:type_name -> tests.SlicesStruct - 7, // 56: tests.ComplexSt.pt_field:type_name -> tests.PointersStruct - 1, // 57: tests.EmbeddedSt1.primitives_struct:type_name -> tests.PrimitivesStruct - 1, // 58: tests.EmbeddedSt2.primitives_struct:type_name -> tests.PrimitivesStruct - 3, // 59: tests.EmbeddedSt2.arrays_struct:type_name -> tests.ArraysStruct - 5, // 60: tests.EmbeddedSt2.slices_struct:type_name -> tests.SlicesStruct - 7, // 61: tests.EmbeddedSt2.pointers_struct:type_name -> tests.PointersStruct - 1, // 62: tests.EmbeddedSt3.primitives_struct:type_name -> tests.PrimitivesStruct - 3, // 63: tests.EmbeddedSt3.arrays_struct:type_name -> tests.ArraysStruct - 5, // 64: tests.EmbeddedSt3.slices_struct:type_name -> tests.SlicesStruct - 7, // 65: tests.EmbeddedSt3.pointers_struct:type_name -> tests.PointersStruct - 0, // 66: tests.EmbeddedSt3.empty_struct:type_name -> tests.EmptyStruct - 1, // 67: tests.EmbeddedSt4.primitives_struct:type_name -> tests.PrimitivesStruct - 3, // 68: tests.EmbeddedSt4.arrays_struct_field:type_name -> tests.ArraysStruct - 5, // 69: tests.EmbeddedSt4.slices_struct:type_name -> tests.SlicesStruct - 7, // 70: tests.EmbeddedSt4.pointers_struct_field:type_name -> tests.PointersStruct - 1, // 71: tests.EmbeddedSt5NameOverride.primitives_struct:type_name -> tests.PrimitivesStruct - 3, // 72: tests.EmbeddedSt5NameOverride.arrays_struct_field:type_name -> tests.ArraysStruct - 5, // 73: tests.EmbeddedSt5NameOverride.slices_struct:type_name -> tests.SlicesStruct - 7, // 74: tests.EmbeddedSt5NameOverride.pointers_struct_field:type_name -> tests.PointersStruct - 18, // 75: tests.AminoMarshalerStruct2.value:type_name -> tests.ReprElem2 - 57, // 76: tests.ReprElem2.value:type_name -> google.protobuf.Any - 15, // 77: tests.AminoMarshalerStruct6.value:type_name -> tests.AminoMarshalerStruct1 - 55, // 78: tests.PrimitivesStructDef.time:type_name -> google.protobuf.Timestamp - 56, // 79: tests.PrimitivesStructDef.duration:type_name -> google.protobuf.Duration - 0, // 80: tests.PrimitivesStructDef.empty:type_name -> tests.EmptyStruct - 1, // 81: tests.PrimitivesStructSl.value:type_name -> tests.PrimitivesStruct - 1, // 82: tests.PrimitivesStructAr.value:type_name -> tests.PrimitivesStruct - 57, // 83: tests.InterfaceFieldsStruct.f1:type_name -> google.protobuf.Any - 57, // 84: tests.InterfaceFieldsStruct.f2:type_name -> google.protobuf.Any - 57, // 85: tests.InterfaceFieldsStruct.f3:type_name -> google.protobuf.Any - 57, // 86: tests.InterfaceFieldsStruct.f4:type_name -> google.protobuf.Any - 38, // 87: tests.TESTS_BytesListList.Value:type_name -> tests.TESTS_BytesList - 56, // 88: tests.TESTS_DurationList.Value:type_name -> google.protobuf.Duration - 0, // 89: tests.TESTS_EmptyStructList.Value:type_name -> tests.EmptyStruct - 55, // 90: tests.TESTS_TimestampList.Value:type_name -> google.protobuf.Timestamp - 91, // [91:91] is the sub-list for method output_type - 91, // [91:91] is the sub-list for method input_type - 91, // [91:91] is the sub-list for extension type_name - 91, // [91:91] is the sub-list for extension extendee - 0, // [0:91] is the sub-list for field type_name -} - -func init() { file_tests_proto_init() } -func file_tests_proto_init() { - if File_tests_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_tests_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmptyStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrimitivesStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShortArraysStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ArraysStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ArraysArraysStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SlicesStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SlicesSlicesStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PointersStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PointerSlicesStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ComplexSt); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmbeddedSt1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmbeddedSt2); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmbeddedSt3); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmbeddedSt4); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmbeddedSt5NameOverride); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerStruct1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReprStruct1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerStruct2); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReprElem2); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerStruct3); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerInt4); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerInt5); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerStruct6); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AminoMarshalerStruct7); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReprElem7); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IntDef); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IntAr); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IntSl); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ByteAr); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ByteSl); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrimitivesStructDef); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrimitivesStructSl); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrimitivesStructAr); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Concrete1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Concrete2); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConcreteTypeDef); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConcreteWrappedBytes); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InterfaceFieldsStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_BytesList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_BytesListList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_DurationList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_EmptyStructList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Fixed32Int32ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Fixed32UInt32ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Fixed64Int64ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Fixed64UInt64ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Int16List); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Int32ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Int64ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_Int8List); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_StringValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_TimestampList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_UInt16List); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_UInt32ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tests_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TESTS_UInt64ValueList); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_tests_proto_rawDesc, - NumEnums: 0, - NumMessages: 55, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_tests_proto_goTypes, - DependencyIndexes: file_tests_proto_depIdxs, - MessageInfos: file_tests_proto_msgTypes, - }.Build() - File_tests_proto = out.File - file_tests_proto_rawDesc = nil - file_tests_proto_goTypes = nil - file_tests_proto_depIdxs = nil -} diff --git a/tm2/pkg/amino/tests/proto3/proto/compat.pb.go b/tm2/pkg/amino/tests/proto3/proto/compat.pb.go deleted file mode 100644 index b03a9273125..00000000000 --- a/tm2/pkg/amino/tests/proto3/proto/compat.pb.go +++ /dev/null @@ -1,1044 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 -// source: proto/compat.proto - -package proto3 - -import ( - reflect "reflect" - sync "sync" - - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type TestInt32Varint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int32 int32 `protobuf:"zigzag32,1,opt,name=Int32,proto3" json:"Int32,omitempty"` -} - -func (x *TestInt32Varint) Reset() { - *x = TestInt32Varint{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TestInt32Varint) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TestInt32Varint) ProtoMessage() {} - -func (x *TestInt32Varint) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TestInt32Varint.ProtoReflect.Descriptor instead. -func (*TestInt32Varint) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{0} -} - -func (x *TestInt32Varint) GetInt32() int32 { - if x != nil { - return x.Int32 - } - return 0 -} - -type TestInt32Fixed struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Fixed32 uint32 `protobuf:"fixed32,1,opt,name=Fixed32,proto3" json:"Fixed32,omitempty"` -} - -func (x *TestInt32Fixed) Reset() { - *x = TestInt32Fixed{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TestInt32Fixed) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TestInt32Fixed) ProtoMessage() {} - -func (x *TestInt32Fixed) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TestInt32Fixed.ProtoReflect.Descriptor instead. -func (*TestInt32Fixed) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{1} -} - -func (x *TestInt32Fixed) GetFixed32() uint32 { - if x != nil { - return x.Fixed32 - } - return 0 -} - -type Test32 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Foo uint32 `protobuf:"fixed32,1,opt,name=foo,proto3" json:"foo,omitempty"` - Bar int32 `protobuf:"zigzag32,2,opt,name=bar,proto3" json:"bar,omitempty"` -} - -func (x *Test32) Reset() { - *x = Test32{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Test32) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Test32) ProtoMessage() {} - -func (x *Test32) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Test32.ProtoReflect.Descriptor instead. -func (*Test32) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{2} -} - -func (x *Test32) GetFoo() uint32 { - if x != nil { - return x.Foo - } - return 0 -} - -func (x *Test32) GetBar() int32 { - if x != nil { - return x.Bar - } - return 0 -} - -type TestFixedInt64 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int64 uint64 `protobuf:"fixed64,1,opt,name=Int64,proto3" json:"Int64,omitempty"` -} - -func (x *TestFixedInt64) Reset() { - *x = TestFixedInt64{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TestFixedInt64) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TestFixedInt64) ProtoMessage() {} - -func (x *TestFixedInt64) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TestFixedInt64.ProtoReflect.Descriptor instead. -func (*TestFixedInt64) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{3} -} - -func (x *TestFixedInt64) GetInt64() uint64 { - if x != nil { - return x.Int64 - } - return 0 -} - -type TestSFixedSInt64 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SInt64 int64 `protobuf:"fixed64,1,opt,name=SInt64,proto3" json:"SInt64,omitempty"` -} - -func (x *TestSFixedSInt64) Reset() { - *x = TestSFixedSInt64{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TestSFixedSInt64) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TestSFixedSInt64) ProtoMessage() {} - -func (x *TestSFixedSInt64) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TestSFixedSInt64.ProtoReflect.Descriptor instead. -func (*TestSFixedSInt64) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{4} -} - -func (x *TestSFixedSInt64) GetSInt64() int64 { - if x != nil { - return x.SInt64 - } - return 0 -} - -type EmbeddedStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - SomethingFixedLen int64 `protobuf:"fixed64,1,opt,name=somethingFixedLen,proto3" json:"somethingFixedLen,omitempty"` -} - -func (x *EmbeddedStruct) Reset() { - *x = EmbeddedStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *EmbeddedStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*EmbeddedStruct) ProtoMessage() {} - -func (x *EmbeddedStruct) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use EmbeddedStruct.ProtoReflect.Descriptor instead. -func (*EmbeddedStruct) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{5} -} - -func (x *EmbeddedStruct) GetSomethingFixedLen() int64 { - if x != nil { - return x.SomethingFixedLen - } - return 0 -} - -type SomeStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // proto3 autom. turns this into a pointer ... - Emb *EmbeddedStruct `protobuf:"bytes,1,opt,name=emb,proto3" json:"emb,omitempty"` -} - -func (x *SomeStruct) Reset() { - *x = SomeStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SomeStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SomeStruct) ProtoMessage() {} - -func (x *SomeStruct) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SomeStruct.ProtoReflect.Descriptor instead. -func (*SomeStruct) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{6} -} - -func (x *SomeStruct) GetEmb() *EmbeddedStruct { - if x != nil { - return x.Emb - } - return nil -} - -type ProtoGotTime struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - T *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=T,proto3" json:"T,omitempty"` -} - -func (x *ProtoGotTime) Reset() { - *x = ProtoGotTime{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProtoGotTime) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProtoGotTime) ProtoMessage() {} - -func (x *ProtoGotTime) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ProtoGotTime.ProtoReflect.Descriptor instead. -func (*ProtoGotTime) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{7} -} - -func (x *ProtoGotTime) GetT() *timestamppb.Timestamp { - if x != nil { - return x.T - } - return nil -} - -type TestInt32 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int32 int32 `protobuf:"varint,1,opt,name=Int32,proto3" json:"Int32,omitempty"` -} - -func (x *TestInt32) Reset() { - *x = TestInt32{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TestInt32) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TestInt32) ProtoMessage() {} - -func (x *TestInt32) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TestInt32.ProtoReflect.Descriptor instead. -func (*TestInt32) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{8} -} - -func (x *TestInt32) GetInt32() int32 { - if x != nil { - return x.Int32 - } - return 0 -} - -type TestInts struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int32 int32 `protobuf:"varint,1,opt,name=Int32,proto3" json:"Int32,omitempty"` - Int64 int64 `protobuf:"varint,2,opt,name=Int64,proto3" json:"Int64,omitempty"` -} - -func (x *TestInts) Reset() { - *x = TestInts{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TestInts) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TestInts) ProtoMessage() {} - -func (x *TestInts) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TestInts.ProtoReflect.Descriptor instead. -func (*TestInts) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{9} -} - -func (x *TestInts) GetInt32() int32 { - if x != nil { - return x.Int32 - } - return 0 -} - -func (x *TestInts) GetInt64() int64 { - if x != nil { - return x.Int64 - } - return 0 -} - -type IntDef struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Val int64 `protobuf:"varint,1,opt,name=val,proto3" json:"val,omitempty"` -} - -func (x *IntDef) Reset() { - *x = IntDef{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IntDef) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IntDef) ProtoMessage() {} - -func (x *IntDef) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IntDef.ProtoReflect.Descriptor instead. -func (*IntDef) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{10} -} - -func (x *IntDef) GetVal() int64 { - if x != nil { - return x.Val - } - return 0 -} - -type IntArr struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Val []int64 `protobuf:"varint,1,rep,packed,name=val,proto3" json:"val,omitempty"` -} - -func (x *IntArr) Reset() { - *x = IntArr{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *IntArr) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*IntArr) ProtoMessage() {} - -func (x *IntArr) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use IntArr.ProtoReflect.Descriptor instead. -func (*IntArr) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{11} -} - -func (x *IntArr) GetVal() []int64 { - if x != nil { - return x.Val - } - return nil -} - -type PrimitivesStruct struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Int32 int32 `protobuf:"varint,3,opt,name=Int32,proto3" json:"Int32,omitempty"` - Int64 int64 `protobuf:"varint,4,opt,name=Int64,proto3" json:"Int64,omitempty"` - Varint int64 `protobuf:"varint,5,opt,name=Varint,proto3" json:"Varint,omitempty"` - // int int - // Byte byte = 4; // this just another varint - // Uint8 uint8 // another varint - // Uint16 uint16 // another one, also the following - // Uint32 uint32 - // Uint64 uint64 - // Uvarint uint64 `binary:"varint"` - // Uint uint - String_ string `protobuf:"bytes,14,opt,name=String,proto3" json:"String,omitempty"` - Bytes []byte `protobuf:"bytes,15,opt,name=Bytes,proto3" json:"Bytes,omitempty"` - Time *timestamppb.Timestamp `protobuf:"bytes,16,opt,name=Time,proto3" json:"Time,omitempty"` -} - -func (x *PrimitivesStruct) Reset() { - *x = PrimitivesStruct{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrimitivesStruct) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrimitivesStruct) ProtoMessage() {} - -func (x *PrimitivesStruct) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrimitivesStruct.ProtoReflect.Descriptor instead. -func (*PrimitivesStruct) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{12} -} - -func (x *PrimitivesStruct) GetInt32() int32 { - if x != nil { - return x.Int32 - } - return 0 -} - -func (x *PrimitivesStruct) GetInt64() int64 { - if x != nil { - return x.Int64 - } - return 0 -} - -func (x *PrimitivesStruct) GetVarint() int64 { - if x != nil { - return x.Varint - } - return 0 -} - -func (x *PrimitivesStruct) GetString_() string { - if x != nil { - return x.String_ - } - return "" -} - -func (x *PrimitivesStruct) GetBytes() []byte { - if x != nil { - return x.Bytes - } - return nil -} - -func (x *PrimitivesStruct) GetTime() *timestamppb.Timestamp { - if x != nil { - return x.Time - } - return nil -} - -type PrimitivesStructSl struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Structs []*PrimitivesStruct `protobuf:"bytes,1,rep,name=Structs,proto3" json:"Structs,omitempty"` -} - -func (x *PrimitivesStructSl) Reset() { - *x = PrimitivesStructSl{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_compat_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrimitivesStructSl) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrimitivesStructSl) ProtoMessage() {} - -func (x *PrimitivesStructSl) ProtoReflect() protoreflect.Message { - mi := &file_proto_compat_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrimitivesStructSl.ProtoReflect.Descriptor instead. -func (*PrimitivesStructSl) Descriptor() ([]byte, []int) { - return file_proto_compat_proto_rawDescGZIP(), []int{13} -} - -func (x *PrimitivesStructSl) GetStructs() []*PrimitivesStruct { - if x != nil { - return x.Structs - } - return nil -} - -var File_proto_compat_proto protoreflect.FileDescriptor - -var file_proto_compat_proto_rawDesc = []byte{ - 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x74, 0x65, 0x73, 0x74, - 0x73, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x27, 0x0a, 0x0f, 0x54, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, - 0x61, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x11, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x22, 0x2a, 0x0a, 0x0e, 0x54, - 0x65, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x46, 0x69, 0x78, 0x65, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x52, 0x07, - 0x46, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x22, 0x2c, 0x0a, 0x06, 0x54, 0x65, 0x73, 0x74, 0x33, - 0x32, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x52, 0x03, - 0x66, 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x11, - 0x52, 0x03, 0x62, 0x61, 0x72, 0x22, 0x26, 0x0a, 0x0e, 0x54, 0x65, 0x73, 0x74, 0x46, 0x69, 0x78, - 0x65, 0x64, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x06, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x22, 0x2a, 0x0a, - 0x10, 0x54, 0x65, 0x73, 0x74, 0x53, 0x46, 0x69, 0x78, 0x65, 0x64, 0x53, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x10, 0x52, 0x06, 0x53, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x22, 0x3e, 0x0a, 0x0e, 0x45, 0x6d, 0x62, - 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x73, - 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x46, 0x69, 0x78, 0x65, 0x64, 0x4c, 0x65, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x10, 0x52, 0x11, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, - 0x67, 0x46, 0x69, 0x78, 0x65, 0x64, 0x4c, 0x65, 0x6e, 0x22, 0x3b, 0x0a, 0x0a, 0x53, 0x6f, 0x6d, - 0x65, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6d, 0x62, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x74, 0x65, 0x73, - 0x74, 0x73, 0x2e, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x52, 0x03, 0x65, 0x6d, 0x62, 0x22, 0x38, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x47, - 0x6f, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x01, 0x54, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x01, 0x54, - 0x22, 0x21, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x12, 0x14, 0x0a, - 0x05, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x49, 0x6e, - 0x74, 0x33, 0x32, 0x22, 0x36, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x73, 0x12, - 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, - 0x49, 0x6e, 0x74, 0x33, 0x32, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x22, 0x1a, 0x0a, 0x06, 0x49, - 0x6e, 0x74, 0x44, 0x65, 0x66, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x03, 0x76, 0x61, 0x6c, 0x22, 0x1a, 0x0a, 0x06, 0x49, 0x6e, 0x74, 0x41, 0x72, - 0x72, 0x12, 0x10, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x03, - 0x76, 0x61, 0x6c, 0x22, 0xb4, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x33, - 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x12, 0x14, - 0x0a, 0x05, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x49, - 0x6e, 0x74, 0x36, 0x34, 0x12, 0x16, 0x0a, 0x06, 0x56, 0x61, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x56, 0x61, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, - 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x54, 0x69, - 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x4d, 0x0a, 0x12, 0x50, 0x72, - 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x53, 0x6c, - 0x12, 0x37, 0x0a, 0x07, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x74, 0x65, 0x73, 0x74, 0x73, 0x2e, - 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x07, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var ( - file_proto_compat_proto_rawDescOnce sync.Once - file_proto_compat_proto_rawDescData = file_proto_compat_proto_rawDesc -) - -func file_proto_compat_proto_rawDescGZIP() []byte { - file_proto_compat_proto_rawDescOnce.Do(func() { - file_proto_compat_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_compat_proto_rawDescData) - }) - return file_proto_compat_proto_rawDescData -} - -var file_proto_compat_proto_msgTypes = make([]protoimpl.MessageInfo, 14) -var file_proto_compat_proto_goTypes = []interface{}{ - (*TestInt32Varint)(nil), // 0: proto3tests.TestInt32Varint - (*TestInt32Fixed)(nil), // 1: proto3tests.TestInt32Fixed - (*Test32)(nil), // 2: proto3tests.Test32 - (*TestFixedInt64)(nil), // 3: proto3tests.TestFixedInt64 - (*TestSFixedSInt64)(nil), // 4: proto3tests.TestSFixedSInt64 - (*EmbeddedStruct)(nil), // 5: proto3tests.EmbeddedStruct - (*SomeStruct)(nil), // 6: proto3tests.SomeStruct - (*ProtoGotTime)(nil), // 7: proto3tests.ProtoGotTime - (*TestInt32)(nil), // 8: proto3tests.TestInt32 - (*TestInts)(nil), // 9: proto3tests.TestInts - (*IntDef)(nil), // 10: proto3tests.IntDef - (*IntArr)(nil), // 11: proto3tests.IntArr - (*PrimitivesStruct)(nil), // 12: proto3tests.PrimitivesStruct - (*PrimitivesStructSl)(nil), // 13: proto3tests.PrimitivesStructSl - (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp -} -var file_proto_compat_proto_depIdxs = []int32{ - 5, // 0: proto3tests.SomeStruct.emb:type_name -> proto3tests.EmbeddedStruct - 14, // 1: proto3tests.ProtoGotTime.T:type_name -> google.protobuf.Timestamp - 14, // 2: proto3tests.PrimitivesStruct.Time:type_name -> google.protobuf.Timestamp - 12, // 3: proto3tests.PrimitivesStructSl.Structs:type_name -> proto3tests.PrimitivesStruct - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name -} - -func init() { file_proto_compat_proto_init() } -func file_proto_compat_proto_init() { - if File_proto_compat_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_proto_compat_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestInt32Varint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestInt32Fixed); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Test32); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestFixedInt64); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestSFixedSInt64); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EmbeddedStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SomeStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProtoGotTime); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestInt32); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestInts); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IntDef); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IntArr); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrimitivesStruct); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_compat_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrimitivesStructSl); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_proto_compat_proto_rawDesc, - NumEnums: 0, - NumMessages: 14, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_proto_compat_proto_goTypes, - DependencyIndexes: file_proto_compat_proto_depIdxs, - MessageInfos: file_proto_compat_proto_msgTypes, - }.Build() - File_proto_compat_proto = out.File - file_proto_compat_proto_rawDesc = nil - file_proto_compat_proto_goTypes = nil - file_proto_compat_proto_depIdxs = nil -} diff --git a/tm2/pkg/libtm/messages/types/messages.pb.go b/tm2/pkg/libtm/messages/types/messages.pb.go deleted file mode 100644 index 5e09d2a1a11..00000000000 --- a/tm2/pkg/libtm/messages/types/messages.pb.go +++ /dev/null @@ -1,543 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v4.25.3 -// source: messages/types/proto/messages.proto - -package types - -import ( - reflect "reflect" - sync "sync" - - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// MessageType defines the types of messages -// that are related to the consensus process -type MessageType int32 - -const ( - MessageType_PROPOSAL MessageType = 0 - MessageType_PREVOTE MessageType = 1 - MessageType_PRECOMMIT MessageType = 2 -) - -// Enum value maps for MessageType. -var ( - MessageType_name = map[int32]string{ - 0: "PROPOSAL", - 1: "PREVOTE", - 2: "PRECOMMIT", - } - MessageType_value = map[string]int32{ - "PROPOSAL": 0, - "PREVOTE": 1, - "PRECOMMIT": 2, - } -) - -func (x MessageType) Enum() *MessageType { - p := new(MessageType) - *p = x - return p -} - -func (x MessageType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (MessageType) Descriptor() protoreflect.EnumDescriptor { - return file_messages_types_proto_messages_proto_enumTypes[0].Descriptor() -} - -func (MessageType) Type() protoreflect.EnumType { - return &file_messages_types_proto_messages_proto_enumTypes[0] -} - -func (x MessageType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use MessageType.Descriptor instead. -func (MessageType) EnumDescriptor() ([]byte, []int) { - return file_messages_types_proto_messages_proto_rawDescGZIP(), []int{0} -} - -// View is the consensus state associated with the message -type View struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // height represents the number of the proposal - Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` - // round represents the round number within a - // specific height (starts from 0) - Round uint64 `protobuf:"varint,2,opt,name=round,proto3" json:"round,omitempty"` -} - -func (x *View) Reset() { - *x = View{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_types_proto_messages_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *View) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*View) ProtoMessage() {} - -func (x *View) ProtoReflect() protoreflect.Message { - mi := &file_messages_types_proto_messages_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use View.ProtoReflect.Descriptor instead. -func (*View) Descriptor() ([]byte, []int) { - return file_messages_types_proto_messages_proto_rawDescGZIP(), []int{0} -} - -func (x *View) GetHeight() uint64 { - if x != nil { - return x.Height - } - return 0 -} - -func (x *View) GetRound() uint64 { - if x != nil { - return x.Round - } - return 0 -} - -// ProposalMessage is the message containing -// the consensus proposal for the view -// -type ProposalMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // view is the current view for the message - // (the view in which the message was sent) - View *View `protobuf:"bytes,1,opt,name=view,proto3" json:"view,omitempty"` - // sender is the message sender (unique identifier) - Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - // signature is the message signature of the sender - Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` - // proposal is the actual consensus proposal - Proposal []byte `protobuf:"bytes,4,opt,name=proposal,proto3" json:"proposal,omitempty"` - // proposalRound is the round associated with the - // proposal in the PROPOSE message. - // NOTE: this round value DOES NOT have - // to match the message view (proposal from an earlier round) - ProposalRound int64 `protobuf:"varint,5,opt,name=proposalRound,proto3" json:"proposalRound,omitempty"` -} - -func (x *ProposalMessage) Reset() { - *x = ProposalMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_types_proto_messages_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProposalMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProposalMessage) ProtoMessage() {} - -func (x *ProposalMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_types_proto_messages_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ProposalMessage.ProtoReflect.Descriptor instead. -func (*ProposalMessage) Descriptor() ([]byte, []int) { - return file_messages_types_proto_messages_proto_rawDescGZIP(), []int{1} -} - -func (x *ProposalMessage) GetView() *View { - if x != nil { - return x.View - } - return nil -} - -func (x *ProposalMessage) GetSender() []byte { - if x != nil { - return x.Sender - } - return nil -} - -func (x *ProposalMessage) GetSignature() []byte { - if x != nil { - return x.Signature - } - return nil -} - -func (x *ProposalMessage) GetProposal() []byte { - if x != nil { - return x.Proposal - } - return nil -} - -func (x *ProposalMessage) GetProposalRound() int64 { - if x != nil { - return x.ProposalRound - } - return 0 -} - -// PrevoteMessage is the message -// containing the consensus proposal prevote. -// The prevote message is pretty light, -// apart from containing the view, it just -// contains a unique identifier of the proposal -// for which this prevote is meant for (ex. proposal hash) -// -type PrevoteMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // view is the current view for the message - // (the view in which the message was sent) - View *View `protobuf:"bytes,1,opt,name=view,proto3" json:"view,omitempty"` - // sender is the message sender (unique identifier) - Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - // signature is the message signature of the sender - Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` - // identifier is the unique identifier for - // the proposal associated with this - // prevote message (ex. proposal hash) - Identifier []byte `protobuf:"bytes,4,opt,name=identifier,proto3" json:"identifier,omitempty"` -} - -func (x *PrevoteMessage) Reset() { - *x = PrevoteMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_types_proto_messages_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrevoteMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrevoteMessage) ProtoMessage() {} - -func (x *PrevoteMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_types_proto_messages_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrevoteMessage.ProtoReflect.Descriptor instead. -func (*PrevoteMessage) Descriptor() ([]byte, []int) { - return file_messages_types_proto_messages_proto_rawDescGZIP(), []int{2} -} - -func (x *PrevoteMessage) GetView() *View { - if x != nil { - return x.View - } - return nil -} - -func (x *PrevoteMessage) GetSender() []byte { - if x != nil { - return x.Sender - } - return nil -} - -func (x *PrevoteMessage) GetSignature() []byte { - if x != nil { - return x.Signature - } - return nil -} - -func (x *PrevoteMessage) GetIdentifier() []byte { - if x != nil { - return x.Identifier - } - return nil -} - -// PrecommitMessage is the message -// containing the consensus proposal precommit. -// The precommit message, same as the prevote message, -// contains a unique identifier for the proposal -// for which this precommit is meant for (ex. proposal hash) -// -type PrecommitMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // view is the current view for the message - // (the view in which the message was sent) - View *View `protobuf:"bytes,1,opt,name=view,proto3" json:"view,omitempty"` - // sender is the message sender (unique identifier) - Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - // signature is the message signature of the sender - Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` - // identifier is the unique identifier for - // the proposal associated with this - // precommit message (ex. proposal hash) - Identifier []byte `protobuf:"bytes,4,opt,name=identifier,proto3" json:"identifier,omitempty"` -} - -func (x *PrecommitMessage) Reset() { - *x = PrecommitMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_types_proto_messages_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PrecommitMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PrecommitMessage) ProtoMessage() {} - -func (x *PrecommitMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_types_proto_messages_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PrecommitMessage.ProtoReflect.Descriptor instead. -func (*PrecommitMessage) Descriptor() ([]byte, []int) { - return file_messages_types_proto_messages_proto_rawDescGZIP(), []int{3} -} - -func (x *PrecommitMessage) GetView() *View { - if x != nil { - return x.View - } - return nil -} - -func (x *PrecommitMessage) GetSender() []byte { - if x != nil { - return x.Sender - } - return nil -} - -func (x *PrecommitMessage) GetSignature() []byte { - if x != nil { - return x.Signature - } - return nil -} - -func (x *PrecommitMessage) GetIdentifier() []byte { - if x != nil { - return x.Identifier - } - return nil -} - -var File_messages_types_proto_messages_proto protoreflect.FileDescriptor - -var file_messages_types_proto_messages_proto_rawDesc = []byte{ - 0x0a, 0x23, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x04, 0x56, 0x69, 0x65, 0x77, 0x12, 0x16, 0x0a, - 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0xa4, 0x01, 0x0a, 0x0f, - 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x19, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05, 0x2e, - 0x56, 0x69, 0x65, 0x77, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, - 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, - 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x6f, 0x75, - 0x6e, 0x64, 0x22, 0x81, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x65, 0x76, 0x6f, 0x74, 0x65, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x65, 0x63, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x04, 0x76, - 0x69, 0x65, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x56, 0x69, 0x65, 0x77, - 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1c, - 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2a, 0x37, 0x0a, 0x0b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x50, - 0x52, 0x4f, 0x50, 0x4f, 0x53, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x45, - 0x56, 0x4f, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x52, 0x45, 0x43, 0x4f, 0x4d, - 0x4d, 0x49, 0x54, 0x10, 0x02, 0x42, 0x11, 0x5a, 0x0f, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_messages_types_proto_messages_proto_rawDescOnce sync.Once - file_messages_types_proto_messages_proto_rawDescData = file_messages_types_proto_messages_proto_rawDesc -) - -func file_messages_types_proto_messages_proto_rawDescGZIP() []byte { - file_messages_types_proto_messages_proto_rawDescOnce.Do(func() { - file_messages_types_proto_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_types_proto_messages_proto_rawDescData) - }) - return file_messages_types_proto_messages_proto_rawDescData -} - -var file_messages_types_proto_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_messages_types_proto_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_messages_types_proto_messages_proto_goTypes = []interface{}{ - (MessageType)(0), // 0: MessageType - (*View)(nil), // 1: View - (*ProposalMessage)(nil), // 2: ProposalMessage - (*PrevoteMessage)(nil), // 3: PrevoteMessage - (*PrecommitMessage)(nil), // 4: PrecommitMessage -} -var file_messages_types_proto_messages_proto_depIdxs = []int32{ - 1, // 0: ProposalMessage.view:type_name -> View - 1, // 1: PrevoteMessage.view:type_name -> View - 1, // 2: PrecommitMessage.view:type_name -> View - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name -} - -func init() { file_messages_types_proto_messages_proto_init() } -func file_messages_types_proto_messages_proto_init() { - if File_messages_types_proto_messages_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_messages_types_proto_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*View); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_types_proto_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProposalMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_types_proto_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrevoteMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_types_proto_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrecommitMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_messages_types_proto_messages_proto_rawDesc, - NumEnums: 1, - NumMessages: 4, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_messages_types_proto_messages_proto_goTypes, - DependencyIndexes: file_messages_types_proto_messages_proto_depIdxs, - EnumInfos: file_messages_types_proto_messages_proto_enumTypes, - MessageInfos: file_messages_types_proto_messages_proto_msgTypes, - }.Build() - File_messages_types_proto_messages_proto = out.File - file_messages_types_proto_messages_proto_rawDesc = nil - file_messages_types_proto_messages_proto_goTypes = nil - file_messages_types_proto_messages_proto_depIdxs = nil -} diff --git a/tm2/pkg/std/package.go b/tm2/pkg/std/package.go index 76e1f9fc4ad..3f71c69f0ce 100644 --- a/tm2/pkg/std/package.go +++ b/tm2/pkg/std/package.go @@ -13,10 +13,6 @@ var Package = amino.RegisterPackage(amino.NewPackage( // Account &BaseAccount{}, "BaseAccount", - // MemFile/MemPackage - MemFile{}, "MemFile", - MemPackage{}, "MemPackage", - // Errors InternalError{}, "InternalError", TxDecodeError{}, "TxDecodeError", diff --git a/tm2/pkg/std/std.proto b/tm2/pkg/std/std.proto index 2fad1eeff38..ead6dcf0113 100644 --- a/tm2/pkg/std/std.proto +++ b/tm2/pkg/std/std.proto @@ -15,17 +15,6 @@ message BaseAccount { uint64 sequence = 5; } -message MemFile { - string name = 1 [json_name = "Name"]; - string body = 2 [json_name = "Body"]; -} - -message MemPackage { - string name = 1 [json_name = "Name"]; - string path = 2 [json_name = "Path"]; - repeated MemFile files = 3 [json_name = "Files"]; -} - message InternalError { } diff --git a/tm2/pkg/telemetry/config/config.go b/tm2/pkg/telemetry/config/config.go index a9aa24d7848..47fc5666342 100644 --- a/tm2/pkg/telemetry/config/config.go +++ b/tm2/pkg/telemetry/config/config.go @@ -19,9 +19,9 @@ type Config struct { func DefaultTelemetryConfig() *Config { return &Config{ MetricsEnabled: false, - MeterName: "gno.land", - ServiceName: "gno.land", - ServiceInstanceID: "gno-node-1", + MeterName: "tm2", + ServiceName: "tm2", + ServiceInstanceID: "tm2-node-1", ExporterEndpoint: "", } } From b849b5a86c46f5f417dcab4bd453e78838717f4b Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:18:00 -0500 Subject: [PATCH 49/64] ci: run gno test with --print-runtime-metrics (#2979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling `--print-runtime-metrics` on the CI triggered a bug. One of our libraries passes without the flag but triggers a panic with the message `allocation limit exceeded` when the flag is present. I suspect this check occurs with the `gno` CLI when the flag is enabled and also on-chain. Therefore, it may be a minor bug affecting local development, particularly for unit tests. Regardless, it deserves investigation. --- Diff too long (47Mb); embedding only the first and last 100 lines. ```console $> go run github.com/gnolang/gno/gnovm/cmd/gno test -v -update-golden-tests -print-runtime-metrics ./examples/gno.land/p/demo/diff === RUN TestMyersDiff === RUN TestMyersDiff/No_difference --- PASS: TestMyersDiff/No_difference (0.00s) === RUN TestMyersDiff/Simple_insertion --- PASS: TestMyersDiff/Simple_insertion (0.00s) === RUN TestMyersDiff/Simple_deletion --- PASS: TestMyersDiff/Simple_deletion (0.00s) === RUN TestMyersDiff/Simple_substitution --- PASS: TestMyersDiff/Simple_substitution (0.00s) === RUN TestMyersDiff/Multiple_changes --- PASS: TestMyersDiff/Multiple_changes (0.00s) === RUN TestMyersDiff/Prefix_and_suffix --- PASS: TestMyersDiff/Prefix_and_suffix (0.00s) === RUN TestMyersDiff/Complete_change --- PASS: TestMyersDiff/Complete_change (0.00s) === RUN TestMyersDiff/Empty_strings --- PASS: TestMyersDiff/Empty_strings (0.00s) === RUN TestMyersDiff/Old_empty --- PASS: TestMyersDiff/Old_empty (0.00s) === RUN TestMyersDiff/New_empty --- PASS: TestMyersDiff/New_empty (0.00s) === RUN TestMyersDiff/non-ascii_(Korean_characters) --- PASS: TestMyersDiff/non-ascii_(Korean_characters) (0.00s) === RUN TestMyersDiff/Emoji_diff --- PASS: TestMyersDiff/Emoji_diff (0.00s) === RUN TestMyersDiff/Mixed_multibyte_and_ASCII --- PASS: TestMyersDiff/Mixed_multibyte_and_ASCII (0.00s) === RUN TestMyersDiff/Chinese_characters --- PASS: TestMyersDiff/Chinese_characters (0.00s) === RUN TestMyersDiff/Combining_characters --- PASS: TestMyersDiff/Combining_characters (0.00s) === RUN TestMyersDiff/Right-to-Left_languages --- PASS: TestMyersDiff/Right-to-Left_languages (0.00s) === RUN TestMyersDiff/Normalization_NFC_and_NFD --- PASS: TestMyersDiff/Normalization_NFC_and_NFD (0.00s) === RUN TestMyersDiff/Case_sensitivity --- PASS: TestMyersDiff/Case_sensitivity (0.00s) === RUN TestMyersDiff/Surrogate_pairs --- PASS: TestMyersDiff/Surrogate_pairs (0.00s) === RUN TestMyersDiff/Control_characters --- PASS: TestMyersDiff/Control_characters (0.00s) === RUN TestMyersDiff/Mixed_scripts --- PASS: TestMyersDiff/Mixed_scripts (0.00s) === RUN TestMyersDiff/Unicode_normalization --- PASS: TestMyersDiff/Unicode_normalization (0.00s) === RUN TestMyersDiff/Directional_marks --- PASS: TestMyersDiff/Directional_marks (0.00s) === RUN TestMyersDiff/Zero-width_characters --- PASS: TestMyersDiff/Zero-width_characters (0.00s) === RUN TestMyersDiff/Worst-case_scenario_(completely_different_strings) ./examples/gno.land/p/demo/diff: test pkg: panic: allocation limit exceeded stack: goroutine 1 [running]: runtime/debug.Stack() /nix/store/05saqcgidraqmn4z82prsp7rbj9hjmwm-go-1.22.5/share/go/src/runtime/debug/stack.go:24 +0x64 main.runTestFiles.func1() /Users/moul/go/src/github.com/gnolang/gno/gnovm/cmd/gno/test.go:427 +0x48 panic({0x102ba10c0?, 0x102d07500?}) /nix/store/05saqcgidraqmn4z82prsp7rbj9hjmwm-go-1.22.5/share/go/src/runtime/panic.go:770 +0x124 github.com/gnolang/gno/gnovm/pkg/gnolang.(*Allocator).Allocate(...) /Users/moul/go/src/github.com/gnolang/gno/gnovm/pkg/gnolang/alloc.go:107 github.com/gnolang/gno/gnovm/pkg/gnolang.(*Allocator).AllocateBlock(...) /Users/moul/go/src/github.com/gnolang/gno/gnovm/pkg/gnolang/alloc.go:157 github.com/gnolang/gno/gnovm/pkg/gnolang.(*Allocator).NewBlock(0x14000010af0, {0x102d27610, 0x14000101b08}, 0x14014a352c0) /Users/moul/go/src/github.com/gnolang/gno/gnovm/pkg/gnolang/alloc.go:291 +0x90 github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).doOpExec(0x140003d0908, 0x1?) /Users/moul/go/src/github.com/gnolang/gno/gnovm/pkg/gnolang/op_exec.go:519 +0x2880 github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).Run(0x140003d0908) /Users/moul/go/src/github.com/gnolang/gno/gnovm/pkg/gnolang/machine.go:1593 +0xaec github.com/gnolang/gno/gnovm/pkg/gnolang.(*Machine).Eval(0x140003d0908, {0x102d1da40, 0x1400b1ae2a0}) /Users/moul/go/src/github.com/gnolang/gno/gnovm/pkg/gnolang/machine.go:884 +0x584 main.runTestFiles(0x140003d0908, 0x140001a5710, {0x140004acbd8, 0x4}, 0x1, 0x1, {0x0, 0x0}, {0x102d20870, 0x140004ab220}) /Users/moul/go/src/github.com/gnolang/gno/gnovm/cmd/gno/test.go:453 +0x2ac main.gnoTestPkg({0x16ddc2824, 0x1f}, {0x1400043cfd0?, 0x1, 0x0?}, {0x0, 0x0, 0x930abcef00000000?}, 0x14000417a80, {0x102d20870, ...}) /Users/moul/go/src/github.com/gnolang/gno/gnovm/cmd/gno/test.go:298 +0xe94 main.execTest(0x14000417a80, {0x1400043cf80?, 0x1?, 0x1?}, {0x102d20870, 0x140004ab220}) /Users/moul/go/src/github.com/gnolang/gno/gnovm/cmd/gno/test.go:197 +0x35c main.newTestCmd.func1({0x0?, 0x140001ae170?}, {0x1400043cf80?, 0x1400040e6c0?, 0x0?}) /Users/moul/go/src/github.com/gnolang/gno/gnovm/cmd/gno/test.go:98 +0x3c github.com/gnolang/gno/tm2/pkg/commands.(*Command).Run(0x14000438f20?, {0x102d136f0?, 0x1033f5e40?}) /Users/moul/go/src/github.com/gnolang/gno/tm2/pkg/commands/command.go:255 +0x17c github.com/gnolang/gno/tm2/pkg/commands.(*Command).Run(0x14000438f20?, {0x102d136f0?, 0x1033f5e40?}) /Users/moul/go/src/github.com/gnolang/gno/tm2/pkg/commands/command.go:259 +0x12c github.com/gnolang/gno/tm2/pkg/commands.(*Command).ParseAndRun(0x14000438f20, {0x102d136f0, 0x1033f5e40}, {0x140001ae130?, 0x140004394a0?, 0x14000439550?}) /Users/moul/go/src/github.com/gnolang/gno/tm2/pkg/commands/command.go:140 +0x4c github.com/gnolang/gno/tm2/pkg/commands.(*Command).Execute(0x102d20870?, {0x102d136f0?, 0x1033f5e40?}, {0x140001ae130?, 0x103311f28?, 0x140000021c0?}) /Users/moul/go/src/github.com/gnolang/gno/tm2/pkg/commands/command.go:117 +0x28 main.main() /Users/moul/go/src/github.com/gnolang/gno/gnovm/cmd/gno/main.go:13 +0x6c gno machine: Machine: CheckTypes: false Op: [OpHalt OpBody OpRangeIter OpPopBlock OpBody OpReturn OpBody OpPopResults OpExec OpBody OpPopResults OpExec OpBody OpRangeIter OpPopResults OpBody OpPopResults OpExec OpBody OpPopResults OpExec OpBody OpDefine OpBody OpForLoop OpForLoop] Values: (len: 10) #9 (MyersDiff func(old string,new string)( []gno.land/p/demo/diff.Edit)) #8 (func(t *testing.T)(){...} testing.testingFunc) #7 (tRunner func(t *testing.T,fn testing.testingFunc,verbose bool)()) #6 (<*testing.T>.Run(t *testing.T,name string,f testing.testingFunc)( bool) func(name string,f testing.testingFunc)( bool)) #5 (slice[(struct{("No difference" string),("abc" string),("abc" string),("abc" string)} struct{name string;old string;new string;expected string}),(struct{("Simple insertion" string),("ac" string),("abc" string),("a[+b]c" string)} struct{name string;old string;new string;expected string}),(struct{("Simple deletion" string),("abc" string),("ac" string),("a[-b]c" string)} struct{name string;old string;new string;expected string}),(struct{("Simple substitution" string),("abc" string),("abd" string),("ab[-c][+d]" string)} struct{name string;old string;new string;expected string}),(struct{("Multiple changes" string),("The quick brown fox jumps over the lazy dog" string),("The quick brown cat jumps over the lazy dog" string),("The quick brown [-fox][+cat] jumps over the lazy dog" string)} struct{name string;old string;new string;expected string}),(struct{("Prefix and suffix" string),("Hello, world!" string),("Hello, beautiful world!" string),("Hello, [+beautiful ]world!" string)} struct{name string;old string;new string;expected string}),(struct{("Complete change" string),("abcdef" string),("ghijkl" string),("[-abcdef][+ghijkl]" string)} struct{name string;old string;new string;expected string}),(struct{("Empty strings" string),("" string),("" string),("" string)} struct{name string;old string;new string;expected string}),(struct{("Old empty" string),("" string),("abc" string),("[+abc]" string)} struct{name string;old string;new string;expected string}),(struct{("New empty" string),("abc" string),("" string),("[-abc]" string)} struct{name string;old string;new string;expected string}),(struct{("non-ascii (Korean characters)" string),("ASCII 문자가 아닌 것도 되나?" string),("ASCII 문자가 아닌 것도 됨." string),("ASCII 문자가 아닌 것도 [-되나?][+됨.]" string)} struct{name string;old string;new string;expected string}),(struct{("Emoji diff" string),("Hello 👋 World 🌍" string),("Hello 👋 Beautiful 🌸 World 🌍" string),("Hello 👋 [+Beautiful 🌸 ]World 🌍" string)} struct{name string;old string;new string;expected string}),(struct{("Mixed multibyte and ASCII" string),("こんにちは World" string),("こんばんは World" string),("こん[-にち][+ばん]は World" string)} struct{name string;old string;new string;expected string}),(struct{("Chinese characters" string),("我喜欢编程" string),("我喜欢看书和编程" string),("我喜欢[+看书和]编程" string)} struct{name string;old string;new string;expected string}),(struct{("Combining characters" string),("é" string),("è" string),("e[-́][+̀]" string)} struct{name string;old string;new string;expected string}),(struct{("Right-to-Left languages" string),("שלום" string),("שלום עולם" string),("שלום[+ עולם]" string)} struct{name string;old string;new string;expected string}),(struct{("Normalization NFC and NFD" string),("é" string),("é" string),("[-é][+é]" string)} struct{name string;old string;new string;expected string}),(struct{("Case sensitivity" string),("abc" string),("Abc" string),("[-a][+A]bc" string)} struct{name string;old string;new string;expected string}),(struct{("Surrogate pairs" string),("Hello 🌍" string),("Hello 🌎" string),("Hello [-🌍][+🌎]" string)} struct{name string;old string;new string;expected string}),(struct{("Control characters" string),("Line1\nLine2" string),("Line1\r\nLine2" string),("Line1[+\r]\nLine2" string)} struct{name string;old string;new string;expected string}),(struct{("Mixed scripts" string),("Hello नमस्ते こんにちは" string),("Hello สวัสดี こんにちは" string),("Hello [-नमस्ते][+สวัสดี] こんにちは" string)} struct{name string;old string;new string;expected string}),(struct{("Unicode normalization" string),("é" string),("é" string),("[-é][+é]" string)} struct{name string;old string;new string;expected string}),(struct{("Directional marks" string),("Hello\u200eworld" string),("Hello\u200fworld" string),("Hello[-\u200e][+\u200f]world" string)} struct{name string;old string;new string;expected string}),(struct{("Zero-width characters" string),("ab\u200bc" string),("abc" string),("ab[-\u200b]c" string)} struct{name string;old string;new string;expected string}),(struct{("Worst-case scenario (completely different strings)" string),("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" string),("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" string),("[-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa][+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb]" string)} struct{name string;old string;new string;expected string}),(struct{("Very long strings" string),("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" string),("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" string),("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[-b][+c]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" string)} struct{name string;old string;new string;expected string})] []struct{name string;old string;new string;expected string}) #4 (TestMyersDiff testing.testingFunc) [...] t: (&(struct{("TestMyersDiff/Worst-case_scenario_(completely_different_strings)" string),(false bool),(false bool),(nil []*testing.T),(&(struct{("TestMyersDiff" string),(false bool),(false bool),(slice[(&(struct{("TestMyersDiff/No_difference" string),(false bool),(false bool),(nil []*testing.T),(0x1400b0a7830 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_insertion" string),(false bool),(false bool),(nil []*testing.T),(0x1400b0a7bf0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_deletion" string),(false bool),(false bool),(nil []*testing.T),(0x14017b42000 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_substitution" string),(false bool),(false bool),(nil []*testing.T),(0x14017b422a0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Multiple_changes" string),(false bool),(false bool),(nil []*testing.T),(0x14017b42510 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Prefix_and_suffix" string),(false bool),(false bool),(nil []*testing.T),(0x14017b42780 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Complete_change" string),(false bool),(false bool),(nil []*testing.T),(0x14017b429f0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Empty_strings" string),(false bool),(false bool),(nil []*testing.T),(0x14017b42c60 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Old_empty" string),(false bool),(false bool),(nil []*testing.T),(0x14017b42ed0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/New_empty" string),(false bool),(false bool),(nil []*testing.T),(0x14017b43140 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/non-ascii_(Korean_characters)" string),(false bool),(false bool),(nil []*testing.T),(0x14017b433b0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Emoji_diff" string),(false bool),(false bool),(nil []*testing.T),(0x14017b43620 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Mixed_multibyte_and_ASCII" string),(false bool),(false bool),(nil []*testing.T),(0x14017b43890 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Chinese_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14017b43b00 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Combining_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14017b43d70 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Right-to-Left_languages" string),(false bool),(false bool),(nil []*testing.T),(0x14017a62060 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Normalization_NFC_and_NFD" string),(false bool),(false bool),(nil []*testing.T),(0x14017a622d0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Case_sensitivity" string),(false bool),(false bool),(nil []*testing.T),(0x14017a62570 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Surrogate_pairs" string),(false bool),(false bool),(nil []*testing.T),(0x14017a627e0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Control_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14017a62a50 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Mixed_scripts" string),(false bool),(false bool),(nil []*testing.T),(0x14017a62cc0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Unicode_normalization" string),(false bool),(false bool),(nil []*testing.T),(0x14017a62f30 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Directional_marks" string),(false bool),(false bool),(nil []*testing.T),(0x14017a631a0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Zero-width_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14017a63410 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(0x14017a63500 *testing.T)] []*testing.T),(nil *testing.T),(nil []uint8),(true bool),(undefined),( string)} testing.T) *testing.T),(nil []uint8),(true bool),(undefined),( string)} testing.T) *testing.T) diff: (undefined) result: (undefined) (static) #10 Block(ID:0000000000000000000000000000000000000000:0,Addr:0x140004dee30,Source:func func(t *(testing)) Run...,Parent:0x1400668ad20) t: (&(struct{("TestMyersDiff" string),(false bool),(false bool),(slice[(&(struct{("TestMyersDiff/No_difference" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d8180 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_insertion" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d8540 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_deletion" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d8930 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_substitution" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d8ba0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Multiple_changes" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d8ed0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Prefix_and_suffix" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d9290 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Complete_change" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d95c0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Empty_strings" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d98f0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Old_empty" string),(false bool),(false bool),(nil []*testing.T),(0x1400d1d9c50 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/New_empty" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb8000 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/non-ascii_(Korean_characters)" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb8270 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Emoji_diff" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb8510 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Mixed_multibyte_and_ASCII" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb8780 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Chinese_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb89f0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Combining_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb8c60 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Right-to-Left_languages" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb8ed0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Normalization_NFC_and_NFD" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb9140 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Case_sensitivity" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb93b0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Surrogate_pairs" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb9620 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Control_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb9890 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Mixed_scripts" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb9b00 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Unicode_normalization" string),(false bool),(false bool),(nil []*testing.T),(0x14014fb9d70 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Directional_marks" string),(false bool),(false bool),(nil []*testing.T),(0x14008bda060 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Zero-width_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14008bda2d0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Worst-case_scenario_(completely_different_strings)" string),(false bool),(false bool),(nil []*testing.T),(0x14008bda540 *testing.T),(nil []uint8),(true bool),(undefined),( string)} testing.T) *testing.T)] []*testing.T),(nil *testing.T),(nil []uint8),(true bool),(undefined),( string)} testing.T) *testing.T) name: ("Worst-case scenario (completely different strings)" string) f: (func(t *testing.T)(){...} testing.testingFunc) fullName: ("TestMyersDiff/Worst-case_scenario_(completely_different_strings)" string) subT: (&(struct{("TestMyersDiff/Worst-case_scenario_(completely_different_strings)" string),(false bool),(false bool),(nil []*testing.T),(&(struct{("TestMyersDiff" string),(false bool),(false bool),(slice[(&(struct{("TestMyersDiff/No_difference" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdac90 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_insertion" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdaf00 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_deletion" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdb170 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Simple_substitution" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdb3e0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Multiple_changes" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdb650 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Prefix_and_suffix" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdb8f0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Complete_change" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdbb60 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Empty_strings" string),(false bool),(false bool),(nil []*testing.T),(0x14008bdbe00 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Old_empty" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6c0f0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/New_empty" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6c360 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/non-ascii_(Korean_characters)" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6c600 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Emoji_diff" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6c870 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Mixed_multibyte_and_ASCII" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6cae0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Chinese_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6cd50 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Combining_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6cfc0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Right-to-Left_languages" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6d230 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Normalization_NFC_and_NFD" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6d4d0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Case_sensitivity" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6d740 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Surrogate_pairs" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6d9b0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Control_characters" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6dc20 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Mixed_scripts" string),(false bool),(false bool),(nil []*testing.T),(0x14008c6de90 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Unicode_normalization" string),(false bool),(false bool),(nil []*testing.T),(0x14008944180 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Directional_marks" string),(false bool),(false bool),(nil []*testing.T),(0x14008944420 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(&(struct{("TestMyersDiff/Zero-width_characters" string),(false bool),(false bool),(nil []*testing.T),(0x140089446c0 *testing.T),(nil []uint8),(true bool),(undefined),("0.00s" string)} testing.T) *testing.T),(0x140089447b0 *testing.T)] []*testing.T),(nil *testing.T),(nil []uint8),(true bool),(undefined),( string)} testing.T) *testing.T),(nil []uint8),(true bool),(undefined),( string)} testing.T) *testing.T) .res_0: (undefined) (static) #8 Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14006babc30,Source:func (t *(T)) Run...,Parent:0x14006bd2330) t: (nil *testing.T) name: ( string) f: (nil testing.testingFunc) fullName: ( string) subT: (nil *testing.T) .res_0: (false bool) #7 Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14006ac65a0,Source:for _, tc, tc.Name == na...,Parent:0x14006766b40) (static) #3 Block(ID:0000000000000000000000000000000000000000:0,Addr:0x140088c8d30,Source:if test.Name == na...,Parent:0x14007895530) #2 Block(ID:0000000000000000000000000000000000000000:0,Addr:0x14006766b40,Source:for _, test, test --- .github/workflows/examples.yml | 2 +- gnovm/cmd/gno/test.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 77d40098900..7c4bb35526f 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -47,7 +47,7 @@ jobs: echo "LOG_LEVEL=debug" >> $GITHUB_ENV echo "LOG_PATH_DIR=$LOG_PATH_DIR" >> $GITHUB_ENV - run: go install -v ./gnovm/cmd/gno - - run: go run ./gnovm/cmd/gno test -v -print-events ./examples/... + - run: go run ./gnovm/cmd/gno test -v -print-runtime-metrics -print-events ./examples/... lint: strategy: fail-fast: false diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index c6feebfd2b5..d54b12f6a4f 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -7,6 +7,7 @@ import ( "flag" "fmt" "log" + "math" "os" "path/filepath" "runtime/debug" @@ -300,7 +301,7 @@ func gnoTestPkg( if printRuntimeMetrics { // from tm2/pkg/sdk/vm/keeper.go // XXX: make maxAllocTx configurable. - maxAllocTx := int64(500 * 1000 * 1000) + maxAllocTx := int64(math.MaxInt64) m.Alloc = gno.NewAllocator(maxAllocTx) } From 49e718c0fb98fe221b8c990b4c539cee221dc4e3 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:32:06 -0500 Subject: [PATCH 50/64] feat: add `p/moul/txlink` + `p/moul/helplink` (#2887) This PR aimed to promote the use of a `p/` library for managing special help links from contracts. It also provided an opportunity for me to realize that our discussion about changing the `$` symbol would require some parsing and detection from the `gnoweb` perspective. If we want a simple library like this one, the goal should be to ideally craft a link to the current package without specifying the realm path. Relative URLs worked well with `?`, but they won't function with `$`. As an alternative, we can have this package look for `std.PrevRealm().PkgAddr` if it is not specified. cc @jeronimoalbi @thehowl @leohhhn Related with #2602 Related with #2876 --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- examples/gno.land/p/moul/helplink/gno.mod | 6 ++ .../gno.land/p/moul/helplink/helplink.gno | 79 +++++++++++++++++++ .../p/moul/helplink/helplink_test.gno | 78 ++++++++++++++++++ examples/gno.land/p/moul/txlink/gno.mod | 3 + examples/gno.land/p/moul/txlink/txlink.gno | 74 +++++++++++++++++ .../gno.land/p/moul/txlink/txlink_test.gno | 37 +++++++++ examples/gno.land/r/demo/boards/board.gno | 5 +- examples/gno.land/r/demo/boards/gno.mod | 1 + examples/gno.land/r/demo/boards/post.gno | 30 +++---- .../gno.land/r/demo/boards/z_0_filetest.gno | 2 +- .../r/demo/boards/z_10_c_filetest.gno | 6 +- .../gno.land/r/demo/boards/z_10_filetest.gno | 2 +- .../r/demo/boards/z_11_d_filetest.gno | 8 +- .../gno.land/r/demo/boards/z_11_filetest.gno | 4 +- .../gno.land/r/demo/boards/z_12_filetest.gno | 2 +- .../gno.land/r/demo/boards/z_2_filetest.gno | 4 +- .../gno.land/r/demo/boards/z_3_filetest.gno | 4 +- .../gno.land/r/demo/boards/z_4_filetest.gno | 6 +- .../gno.land/r/demo/boards/z_5_c_filetest.gno | 4 +- .../gno.land/r/demo/boards/z_5_filetest.gno | 6 +- .../gno.land/r/demo/boards/z_6_filetest.gno | 8 +- .../gno.land/r/demo/boards/z_7_filetest.gno | 2 +- .../gno.land/r/demo/boards/z_8_filetest.gno | 4 +- .../gno.land/r/demo/boards/z_9_filetest.gno | 2 +- 24 files changed, 327 insertions(+), 50 deletions(-) create mode 100644 examples/gno.land/p/moul/helplink/gno.mod create mode 100644 examples/gno.land/p/moul/helplink/helplink.gno create mode 100644 examples/gno.land/p/moul/helplink/helplink_test.gno create mode 100644 examples/gno.land/p/moul/txlink/gno.mod create mode 100644 examples/gno.land/p/moul/txlink/txlink.gno create mode 100644 examples/gno.land/p/moul/txlink/txlink_test.gno diff --git a/examples/gno.land/p/moul/helplink/gno.mod b/examples/gno.land/p/moul/helplink/gno.mod new file mode 100644 index 00000000000..1b106749260 --- /dev/null +++ b/examples/gno.land/p/moul/helplink/gno.mod @@ -0,0 +1,6 @@ +module gno.land/p/moul/helplink + +require ( + gno.land/p/demo/urequire v0.0.0-latest + gno.land/p/moul/txlink v0.0.0-latest +) diff --git a/examples/gno.land/p/moul/helplink/helplink.gno b/examples/gno.land/p/moul/helplink/helplink.gno new file mode 100644 index 00000000000..b9ac8e102b9 --- /dev/null +++ b/examples/gno.land/p/moul/helplink/helplink.gno @@ -0,0 +1,79 @@ +// Package helplink provides utilities for creating help page links compatible +// with Gnoweb, Gnobro, and other clients that support the Gno contracts' +// flavored Markdown format. +// +// This package simplifies the generation of dynamic, context-sensitive help +// links, enabling users to navigate relevant documentation seamlessly within +// the Gno ecosystem. +// +// For a more lightweight alternative, consider using p/moul/txlink. +// +// The primary functions — Func, FuncURL, and Home — are intended for use with +// the "relative realm". When specifying a custom Realm, you can create links +// that utilize either the current realm path or a fully qualified path to +// another realm. +package helplink + +import ( + "strings" + + "gno.land/p/moul/txlink" +) + +const chainDomain = "gno.land" // XXX: std.ChainDomain (#2911) + +// Func returns a markdown link for the specific function with optional +// key-value arguments, for the current realm. +func Func(title string, fn string, args ...string) string { + return Realm("").Func(title, fn, args...) +} + +// FuncURL returns a URL for the specified function with optional key-value +// arguments, for the current realm. +func FuncURL(fn string, args ...string) string { + return Realm("").FuncURL(fn, args...) +} + +// Home returns the URL for the help homepage of the current realm. +func Home() string { + return Realm("").Home() +} + +// Realm represents a specific realm for generating help links. +type Realm string + +// prefix returns the URL prefix for the realm. +func (r Realm) prefix() string { + // relative + if r == "" { + return "" + } + + // local realm -> /realm + realm := string(r) + if strings.Contains(realm, chainDomain) { + return strings.TrimPrefix(realm, chainDomain) + } + + // remote realm -> https://remote.land/realm + return "https://" + string(r) +} + +// Func returns a markdown link for the specified function with optional +// key-value arguments. +func (r Realm) Func(title string, fn string, args ...string) string { + // XXX: escape title + return "[" + title + "](" + r.FuncURL(fn, args...) + ")" +} + +// FuncURL returns a URL for the specified function with optional key-value +// arguments. +func (r Realm) FuncURL(fn string, args ...string) string { + tlr := txlink.Realm(r) + return tlr.URL(fn, args...) +} + +// Home returns the base help URL for the specified realm. +func (r Realm) Home() string { + return r.prefix() + "?help" +} diff --git a/examples/gno.land/p/moul/helplink/helplink_test.gno b/examples/gno.land/p/moul/helplink/helplink_test.gno new file mode 100644 index 00000000000..07111158a98 --- /dev/null +++ b/examples/gno.land/p/moul/helplink/helplink_test.gno @@ -0,0 +1,78 @@ +package helplink + +import ( + "testing" + + "gno.land/p/demo/urequire" +) + +func TestFunc(t *testing.T) { + tests := []struct { + title string + fn string + args []string + want string + realm Realm + }{ + {"Example", "foo", []string{"bar", "1", "baz", "2"}, "[Example](?help&__func=foo&bar=1&baz=2)", ""}, + {"Realm Example", "foo", []string{"bar", "1", "baz", "2"}, "[Realm Example](/r/lorem/ipsum?help&__func=foo&bar=1&baz=2)", "gno.land/r/lorem/ipsum"}, + {"Single Arg", "testFunc", []string{"key", "value"}, "[Single Arg](?help&__func=testFunc&key=value)", ""}, + {"No Args", "noArgsFunc", []string{}, "[No Args](?help&__func=noArgsFunc)", ""}, + {"Odd Args", "oddArgsFunc", []string{"key"}, "[Odd Args](?help&__func=oddArgsFunc)", ""}, + } + + for _, tt := range tests { + t.Run(tt.title, func(t *testing.T) { + got := tt.realm.Func(tt.title, tt.fn, tt.args...) + urequire.Equal(t, tt.want, got) + }) + } +} + +func TestFuncURL(t *testing.T) { + tests := []struct { + fn string + args []string + want string + realm Realm + }{ + {"foo", []string{"bar", "1", "baz", "2"}, "?help&__func=foo&bar=1&baz=2", ""}, + {"testFunc", []string{"key", "value"}, "?help&__func=testFunc&key=value", ""}, + {"noArgsFunc", []string{}, "?help&__func=noArgsFunc", ""}, + {"oddArgsFunc", []string{"key"}, "?help&__func=oddArgsFunc", ""}, + {"foo", []string{"bar", "1", "baz", "2"}, "/r/lorem/ipsum?help&__func=foo&bar=1&baz=2", "gno.land/r/lorem/ipsum"}, + {"testFunc", []string{"key", "value"}, "/r/lorem/ipsum?help&__func=testFunc&key=value", "gno.land/r/lorem/ipsum"}, + {"noArgsFunc", []string{}, "/r/lorem/ipsum?help&__func=noArgsFunc", "gno.land/r/lorem/ipsum"}, + {"oddArgsFunc", []string{"key"}, "/r/lorem/ipsum?help&__func=oddArgsFunc", "gno.land/r/lorem/ipsum"}, + {"foo", []string{"bar", "1", "baz", "2"}, "https://gno.world/r/lorem/ipsum?help&__func=foo&bar=1&baz=2", "gno.world/r/lorem/ipsum"}, + {"testFunc", []string{"key", "value"}, "https://gno.world/r/lorem/ipsum?help&__func=testFunc&key=value", "gno.world/r/lorem/ipsum"}, + {"noArgsFunc", []string{}, "https://gno.world/r/lorem/ipsum?help&__func=noArgsFunc", "gno.world/r/lorem/ipsum"}, + {"oddArgsFunc", []string{"key"}, "https://gno.world/r/lorem/ipsum?help&__func=oddArgsFunc", "gno.world/r/lorem/ipsum"}, + } + + for _, tt := range tests { + title := tt.fn + t.Run(title, func(t *testing.T) { + got := tt.realm.FuncURL(tt.fn, tt.args...) + urequire.Equal(t, tt.want, got) + }) + } +} + +func TestHome(t *testing.T) { + tests := []struct { + realm Realm + want string + }{ + {"", "?help"}, + {"gno.land/r/lorem/ipsum", "/r/lorem/ipsum?help"}, + {"gno.world/r/lorem/ipsum", "https://gno.world/r/lorem/ipsum?help"}, + } + + for _, tt := range tests { + t.Run(string(tt.realm), func(t *testing.T) { + got := tt.realm.Home() + urequire.Equal(t, tt.want, got) + }) + } +} diff --git a/examples/gno.land/p/moul/txlink/gno.mod b/examples/gno.land/p/moul/txlink/gno.mod new file mode 100644 index 00000000000..6110464316f --- /dev/null +++ b/examples/gno.land/p/moul/txlink/gno.mod @@ -0,0 +1,3 @@ +module gno.land/p/moul/txlink + +require gno.land/p/demo/urequire v0.0.0-latest diff --git a/examples/gno.land/p/moul/txlink/txlink.gno b/examples/gno.land/p/moul/txlink/txlink.gno new file mode 100644 index 00000000000..26656e67f29 --- /dev/null +++ b/examples/gno.land/p/moul/txlink/txlink.gno @@ -0,0 +1,74 @@ +// Package txlink provides utilities for creating transaction-related links +// compatible with Gnoweb, Gnobro, and other clients within the Gno ecosystem. +// +// This package is optimized for generating lightweight transaction links with +// flexible arguments, allowing users to build dynamic links that integrate +// seamlessly with various Gno clients. +// +// The primary function, URL, is designed to produce markdown links for +// transaction functions in the current "relative realm". By specifying a custom +// Realm, you can generate links that either use the current realm path or a +// fully qualified path for another realm. +// +// This package is a streamlined alternative to helplink, providing similar +// functionality for transaction links without the full feature set of helplink. +package txlink + +import ( + "std" + "strings" +) + +const chainDomain = "gno.land" // XXX: std.ChainDomain (#2911) + +// URL returns a URL for the specified function with optional key-value +// arguments, for the current realm. +func URL(fn string, args ...string) string { + return Realm("").URL(fn, args...) +} + +// Realm represents a specific realm for generating tx links. +type Realm string + +// prefix returns the URL prefix for the realm. +func (r Realm) prefix() string { + // relative + if r == "" { + curPath := std.CurrentRealm().PkgPath() + return strings.TrimPrefix(curPath, chainDomain) + } + + // local realm -> /realm + realm := string(r) + if strings.Contains(realm, chainDomain) { + return strings.TrimPrefix(realm, chainDomain) + } + + // remote realm -> https://remote.land/realm + return "https://" + string(r) +} + +// URL returns a URL for the specified function with optional key-value +// arguments. +func (r Realm) URL(fn string, args ...string) string { + // Start with the base query + url := r.prefix() + "?help&__func=" + fn + + // Check if args length is even + if len(args)%2 != 0 { + // If not even, we can choose to handle the error here. + // For example, we can just return the URL without appending + // more args. + return url + } + + // Append key-value pairs to the URL + for i := 0; i < len(args); i += 2 { + key := args[i] + value := args[i+1] + // XXX: escape keys and args + url += "&" + key + "=" + value + } + + return url +} diff --git a/examples/gno.land/p/moul/txlink/txlink_test.gno b/examples/gno.land/p/moul/txlink/txlink_test.gno new file mode 100644 index 00000000000..7a460889148 --- /dev/null +++ b/examples/gno.land/p/moul/txlink/txlink_test.gno @@ -0,0 +1,37 @@ +package txlink + +import ( + "testing" + + "gno.land/p/demo/urequire" +) + +func TestURL(t *testing.T) { + tests := []struct { + fn string + args []string + want string + realm Realm + }{ + {"foo", []string{"bar", "1", "baz", "2"}, "?help&__func=foo&bar=1&baz=2", ""}, + {"testFunc", []string{"key", "value"}, "?help&__func=testFunc&key=value", ""}, + {"noArgsFunc", []string{}, "?help&__func=noArgsFunc", ""}, + {"oddArgsFunc", []string{"key"}, "?help&__func=oddArgsFunc", ""}, + {"foo", []string{"bar", "1", "baz", "2"}, "/r/lorem/ipsum?help&__func=foo&bar=1&baz=2", "gno.land/r/lorem/ipsum"}, + {"testFunc", []string{"key", "value"}, "/r/lorem/ipsum?help&__func=testFunc&key=value", "gno.land/r/lorem/ipsum"}, + {"noArgsFunc", []string{}, "/r/lorem/ipsum?help&__func=noArgsFunc", "gno.land/r/lorem/ipsum"}, + {"oddArgsFunc", []string{"key"}, "/r/lorem/ipsum?help&__func=oddArgsFunc", "gno.land/r/lorem/ipsum"}, + {"foo", []string{"bar", "1", "baz", "2"}, "https://gno.world/r/lorem/ipsum?help&__func=foo&bar=1&baz=2", "gno.world/r/lorem/ipsum"}, + {"testFunc", []string{"key", "value"}, "https://gno.world/r/lorem/ipsum?help&__func=testFunc&key=value", "gno.world/r/lorem/ipsum"}, + {"noArgsFunc", []string{}, "https://gno.world/r/lorem/ipsum?help&__func=noArgsFunc", "gno.world/r/lorem/ipsum"}, + {"oddArgsFunc", []string{"key"}, "https://gno.world/r/lorem/ipsum?help&__func=oddArgsFunc", "gno.world/r/lorem/ipsum"}, + } + + for _, tt := range tests { + title := tt.fn + t.Run(title, func(t *testing.T) { + got := tt.realm.URL(tt.fn, tt.args...) + urequire.Equal(t, tt.want, got) + }) + } +} diff --git a/examples/gno.land/r/demo/boards/board.gno b/examples/gno.land/r/demo/boards/board.gno index a9cf56c2a91..79b27da84b2 100644 --- a/examples/gno.land/r/demo/boards/board.gno +++ b/examples/gno.land/r/demo/boards/board.gno @@ -6,6 +6,7 @@ import ( "time" "gno.land/p/demo/avl" + "gno.land/p/moul/txlink" ) //---------------------------------------- @@ -134,7 +135,5 @@ func (board *Board) GetURLFromThreadAndReplyID(threadID, replyID PostID) string } func (board *Board) GetPostFormURL() string { - return "/r/demo/boards?help&__func=CreateThread" + - "&bid=" + board.id.String() + - "&body.type=textarea" + return txlink.URL("CreateThread", "bid", board.id.String()) } diff --git a/examples/gno.land/r/demo/boards/gno.mod b/examples/gno.land/r/demo/boards/gno.mod index 434ad019883..24fea7ce853 100644 --- a/examples/gno.land/r/demo/boards/gno.mod +++ b/examples/gno.land/r/demo/boards/gno.mod @@ -2,5 +2,6 @@ module gno.land/r/demo/boards require ( gno.land/p/demo/avl v0.0.0-latest + gno.land/p/moul/txlink v0.0.0-latest gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/boards/post.gno b/examples/gno.land/r/demo/boards/post.gno index f35cf23628c..95d4b2977ba 100644 --- a/examples/gno.land/r/demo/boards/post.gno +++ b/examples/gno.land/r/demo/boards/post.gno @@ -6,6 +6,7 @@ import ( "time" "gno.land/p/demo/avl" + "gno.land/p/moul/txlink" ) //---------------------------------------- @@ -155,27 +156,26 @@ func (post *Post) GetURL() string { } func (post *Post) GetReplyFormURL() string { - return "/r/demo/boards?help&__func=CreateReply" + - "&bid=" + post.board.id.String() + - "&threadid=" + post.threadID.String() + - "&postid=" + post.id.String() + - "&body.type=textarea" + return txlink.URL("CreateReply", + "bid", post.board.id.String(), + "threadid", post.threadID.String(), + "postid", post.id.String(), + ) } func (post *Post) GetRepostFormURL() string { - return "/r/demo/boards?help&__func=CreateRepost" + - "&bid=" + post.board.id.String() + - "&postid=" + post.id.String() + - "&title.type=textarea" + - "&body.type=textarea" + - "&dstBoardID.type=textarea" + return txlink.URL("CreateRepost", + "bid", post.board.id.String(), + "postid", post.id.String(), + ) } func (post *Post) GetDeleteFormURL() string { - return "/r/demo/boards?help&__func=DeletePost" + - "&bid=" + post.board.id.String() + - "&threadid=" + post.threadID.String() + - "&postid=" + post.id.String() + return txlink.URL("DeletePost", + "bid", post.board.id.String(), + "threadid", post.threadID.String(), + "postid", post.id.String(), + ) } func (post *Post) RenderSummary() string { diff --git a/examples/gno.land/r/demo/boards/z_0_filetest.gno b/examples/gno.land/r/demo/boards/z_0_filetest.gno index e20964d50b7..cdf136be590 100644 --- a/examples/gno.land/r/demo/boards/z_0_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_0_filetest.gno @@ -24,7 +24,7 @@ func main() { } // Output: -// \[[post](/r/demo/boards?help&__func=CreateThread&bid=1&body.type=textarea)] +// \[[post](/r/demo/boards?help&__func=CreateThread&bid=1)] // // ---------------------------------------- // ## [First Post (title)](/r/demo/boards:test_board/1) diff --git a/examples/gno.land/r/demo/boards/z_10_c_filetest.gno b/examples/gno.land/r/demo/boards/z_10_c_filetest.gno index 8555af0b576..cc8d188f727 100644 --- a/examples/gno.land/r/demo/boards/z_10_c_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_10_c_filetest.gno @@ -35,14 +35,14 @@ func main() { // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] // // > First reply of the First post // > -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] // // ---------------------------------------------------- // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] diff --git a/examples/gno.land/r/demo/boards/z_10_filetest.gno b/examples/gno.land/r/demo/boards/z_10_filetest.gno index 548b5865f65..0a4626003d1 100644 --- a/examples/gno.land/r/demo/boards/z_10_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_10_filetest.gno @@ -33,7 +33,7 @@ func main() { // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] // // ---------------------------------------------------- // thread does not exist with id: 1 diff --git a/examples/gno.land/r/demo/boards/z_11_d_filetest.gno b/examples/gno.land/r/demo/boards/z_11_d_filetest.gno index c114e769ab1..04dd6bfb547 100644 --- a/examples/gno.land/r/demo/boards/z_11_d_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_11_d_filetest.gno @@ -35,18 +35,18 @@ func main() { // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] // // > First reply of the First post // > -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] // // ---------------------------------------------------- // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] // // > Edited: First reply of the First post // > -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] diff --git a/examples/gno.land/r/demo/boards/z_11_filetest.gno b/examples/gno.land/r/demo/boards/z_11_filetest.gno index 4cbdeeca4c3..0974991b814 100644 --- a/examples/gno.land/r/demo/boards/z_11_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_11_filetest.gno @@ -33,10 +33,10 @@ func main() { // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] // // ---------------------------------------------------- // # Edited: First Post in (title) // // Edited: Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] diff --git a/examples/gno.land/r/demo/boards/z_12_filetest.gno b/examples/gno.land/r/demo/boards/z_12_filetest.gno index 4ea75b27753..8ae1c99ffbb 100644 --- a/examples/gno.land/r/demo/boards/z_12_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_12_filetest.gno @@ -30,7 +30,7 @@ func main() { // Output: // 1 -// \[[post](/r/demo/boards?help&__func=CreateThread&bid=2&body.type=textarea)] +// \[[post](/r/demo/boards?help&__func=CreateThread&bid=2)] // // ---------------------------------------- // Repost: Check this out diff --git a/examples/gno.land/r/demo/boards/z_2_filetest.gno b/examples/gno.land/r/demo/boards/z_2_filetest.gno index f0d53204e38..037a855eab1 100644 --- a/examples/gno.land/r/demo/boards/z_2_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_2_filetest.gno @@ -32,7 +32,7 @@ func main() { // # Second Post (title) // // Body of the second post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] // // > Reply of the second post -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] diff --git a/examples/gno.land/r/demo/boards/z_3_filetest.gno b/examples/gno.land/r/demo/boards/z_3_filetest.gno index 021ae10b825..79770aa1cec 100644 --- a/examples/gno.land/r/demo/boards/z_3_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_3_filetest.gno @@ -34,7 +34,7 @@ func main() { // # Second Post (title) // // Body of the second post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] // // > Reply of the second post -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] diff --git a/examples/gno.land/r/demo/boards/z_4_filetest.gno b/examples/gno.land/r/demo/boards/z_4_filetest.gno index f0620c28c9d..61e4681f202 100644 --- a/examples/gno.land/r/demo/boards/z_4_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_4_filetest.gno @@ -37,13 +37,13 @@ func main() { // # Second Post (title) // // Body of the second post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] // // > Reply of the second post -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] // // > Second reply of the second post -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=4&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=4)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=4)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=4)] // Realm: // switchrealm["gno.land/r/demo/users"] diff --git a/examples/gno.land/r/demo/boards/z_5_c_filetest.gno b/examples/gno.land/r/demo/boards/z_5_c_filetest.gno index 176b1d89015..440daa6238d 100644 --- a/examples/gno.land/r/demo/boards/z_5_c_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_5_c_filetest.gno @@ -33,7 +33,7 @@ func main() { // # First Post (title) // // Body of the first post. (body) -// \- [g1w3jhxapjta047h6lta047h6lta047h6laqcyu4](/r/demo/users:g1w3jhxapjta047h6lta047h6lta047h6laqcyu4), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] +// \- [g1w3jhxapjta047h6lta047h6lta047h6laqcyu4](/r/demo/users:g1w3jhxapjta047h6lta047h6lta047h6laqcyu4), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=1)] // // > Reply of the first post -// > \- [g1w3jhxapjta047h6lta047h6lta047h6laqcyu4](/r/demo/users:g1w3jhxapjta047h6lta047h6lta047h6laqcyu4), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] +// > \- [g1w3jhxapjta047h6lta047h6lta047h6laqcyu4](/r/demo/users:g1w3jhxapjta047h6lta047h6lta047h6laqcyu4), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=1&postid=2)] diff --git a/examples/gno.land/r/demo/boards/z_5_filetest.gno b/examples/gno.land/r/demo/boards/z_5_filetest.gno index c326d961c91..9d30d9aaa72 100644 --- a/examples/gno.land/r/demo/boards/z_5_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_5_filetest.gno @@ -33,11 +33,11 @@ func main() { // # Second Post (title) // // Body of the second post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] // // > Reply of the second post -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] // // > Second reply of the second post // > -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=4&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=4)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=4)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=4)] diff --git a/examples/gno.land/r/demo/boards/z_6_filetest.gno b/examples/gno.land/r/demo/boards/z_6_filetest.gno index b7de2d08bf9..fb7f9a31772 100644 --- a/examples/gno.land/r/demo/boards/z_6_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_6_filetest.gno @@ -35,15 +35,15 @@ func main() { // # Second Post (title) // // Body of the second post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2&body.type=textarea)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2&title.type=textarea&body.type=textarea&dstBoardID.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2)] \[[repost](/r/demo/boards?help&__func=CreateRepost&bid=1&postid=2)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=2)] // // > Reply of the second post -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] // > // > > First reply of the first reply // > > -// > > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/5) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=5&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=5)] +// > > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/5) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=5)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=5)] // // > Second reply of the second post // > -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=4&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=4)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=4)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=4)] diff --git a/examples/gno.land/r/demo/boards/z_7_filetest.gno b/examples/gno.land/r/demo/boards/z_7_filetest.gno index f1d41aa1723..7df06fd760a 100644 --- a/examples/gno.land/r/demo/boards/z_7_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_7_filetest.gno @@ -22,7 +22,7 @@ func main() { } // Output: -// \[[post](/r/demo/boards?help&__func=CreateThread&bid=1&body.type=textarea)] +// \[[post](/r/demo/boards?help&__func=CreateThread&bid=1)] // // ---------------------------------------- // ## [First Post (title)](/r/demo/boards:test_board/1) diff --git a/examples/gno.land/r/demo/boards/z_8_filetest.gno b/examples/gno.land/r/demo/boards/z_8_filetest.gno index 18ad64083f4..02ce2c4fcef 100644 --- a/examples/gno.land/r/demo/boards/z_8_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_8_filetest.gno @@ -35,10 +35,10 @@ func main() { // _[see thread](/r/demo/boards:test_board/2)_ // // Reply of the second post -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=3)] // // _[see all 1 replies](/r/demo/boards:test_board/2/3)_ // // > First reply of the first reply // > -// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/5) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=5&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=5)] +// > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/5) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=5)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=1&threadid=2&postid=5)] diff --git a/examples/gno.land/r/demo/boards/z_9_filetest.gno b/examples/gno.land/r/demo/boards/z_9_filetest.gno index 10a1444fd35..823318a5e48 100644 --- a/examples/gno.land/r/demo/boards/z_9_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_9_filetest.gno @@ -34,4 +34,4 @@ func main() { // # First Post in (title) // // Body of the first post. (body) -// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:second_board/1/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=2&threadid=1&postid=1&body.type=textarea)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=2&threadid=1&postid=1)] +// \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:second_board/1/1) \[[reply](/r/demo/boards?help&__func=CreateReply&bid=2&threadid=1&postid=1)] \[[x](/r/demo/boards?help&__func=DeletePost&bid=2&threadid=1&postid=1)] From cfbaff2affb64bc0317916c302cf1dc3bae4d516 Mon Sep 17 00:00:00 2001 From: Morgan Date: Fri, 25 Oct 2024 16:43:08 -0500 Subject: [PATCH 51/64] ci: benchmark only BenchmarkBenchdata (#3007) A bit radical, but I'm open to other benchmarks we should include. Essentially, in an effort to have a small amount of meaningful benchmarks, I'd like for these to only be those in BenchmarkBenchdata. Yes, I recognize this is tooting my own horn, but I think they are good benchmarks that tell us, overall, if the GnoVM on a few reference programs got slower or faster, and I found them useful in the past while doing manual execution. Most other benchmarks are micro-benchmarks, which aren't likely to change often or to give us useful insight. I'm open to suggestions for others that make sense to be tracked, but I think it's for the better if we keep the number low so the CI for benchmarks can run in just a few minutes. --- .github/workflows/benchmark-master-push.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark-master-push.yml b/.github/workflows/benchmark-master-push.yml index 09978a0ae5c..bde6e623a88 100644 --- a/.github/workflows/benchmark-master-push.yml +++ b/.github/workflows/benchmark-master-push.yml @@ -34,9 +34,12 @@ jobs: go-version: "1.22.x" - name: Run benchmark + # add more benchmarks by adding additional lines for different packages; + # or modify the -bench regexp. run: | - go test -benchmem -bench=. ./... -run=^$ \ - -cpu 1,2 -timeout 50m | tee benchmarks.txt + set -xeuo pipefail && ( + go test ./gnovm/pkg/gnolang -bench='BenchmarkBenchdata' -benchmem -run='^$' -v -cpu=1,2 + ) | tee benchmarks.txt - name: Download previous benchmark data uses: actions/cache@v4 From 2838ad1a3c3b9795990257cd46f08fc04b2fb3a3 Mon Sep 17 00:00:00 2001 From: Morgan Date: Fri, 25 Oct 2024 16:45:46 -0500 Subject: [PATCH 52/64] ci: add workflow to ensure go.mod files are tidied (#3025)
    Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
    --- .github/workflows/mod-tidy.yml | 26 +++++++++++++++++++++++++ tm2/pkg/amino/tests/proto3/proto/doc.go | 3 +++ 2 files changed, 29 insertions(+) create mode 100644 .github/workflows/mod-tidy.yml create mode 100644 tm2/pkg/amino/tests/proto3/proto/doc.go diff --git a/.github/workflows/mod-tidy.yml b/.github/workflows/mod-tidy.yml new file mode 100644 index 00000000000..118761bddf9 --- /dev/null +++ b/.github/workflows/mod-tidy.yml @@ -0,0 +1,26 @@ +name: Ensure go.mods are tidied + +on: + push: + branches: + - master + workflow_dispatch: + pull_request: + +jobs: + main: + name: Ensure go.mods are tidied + runs-on: ubuntu-latest + steps: + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ inputs.go-version }} + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check go.mod files are up to date + working-directory: ${{ inputs.modulepath }} + run: | + make tidy VERIFY_GO_SUMS=true diff --git a/tm2/pkg/amino/tests/proto3/proto/doc.go b/tm2/pkg/amino/tests/proto3/proto/doc.go new file mode 100644 index 00000000000..909d94e7e7f --- /dev/null +++ b/tm2/pkg/amino/tests/proto3/proto/doc.go @@ -0,0 +1,3 @@ +// This file ensures there is at least one go file in this dir at all times. + +package proto3 From 534e65238a6525532e4ef5cd13b238e3416c1714 Mon Sep 17 00:00:00 2001 From: Mikael VALLENET Date: Sun, 27 Oct 2024 20:50:04 +0100 Subject: [PATCH 53/64] docs: fix tm2 broken link (#3034) --- tm2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tm2/README.md b/tm2/README.md index 0f6e0052933..2addfe8f550 100644 --- a/tm2/README.md +++ b/tm2/README.md @@ -35,7 +35,7 @@ - MISSION: be the basis for improving the encoding standard from proto3, because proto3 length-prefixing is slow, and we need "proto4" or "amino2". - LOOK at the auto-generated proto files! - https://github.com/gnolang/gno/blob/master/pkgs/bft/consensus/types/cstypes.proto + https://github.com/gnolang/gno/blob/master/tm2/pkg/bft/consensus/types/cstypes.proto for example. - There was work to remove this from the CosmosSDK because Amino wasn't ready, but now that it is, it makes sense to incorporate it into From d03581ed748b5f04574b92ff8725957c6b41deca Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 28 Oct 2024 07:51:18 -0500 Subject: [PATCH 54/64] ci: don't test verbosely (#3026) Let's remove the noise in the tests. This will make sure the logs only show the errors when they happen. --- .github/workflows/test_template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_template.yml b/.github/workflows/test_template.yml index 18911415087..38fa10e096b 100644 --- a/.github/workflows/test_template.yml +++ b/.github/workflows/test_template.yml @@ -42,7 +42,7 @@ jobs: # confusing and meticulous. There will be some improvements in Go # 1.23 regarding coverage, so we can use this as a workaround until # then. - go test -covermode=atomic -timeout ${{ inputs.tests-timeout }} -v ./... -test.gocoverdir=$GOCOVERDIR + go test -covermode=atomic -timeout ${{ inputs.tests-timeout }} ./... -test.gocoverdir=$GOCOVERDIR # Print results (set +x; echo 'go coverage results:') From 12bd8da50dc13361206adb916d465220506861b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20=C5=BDivkovi=C4=87?= Date: Tue, 29 Oct 2024 15:18:10 +0100 Subject: [PATCH 55/64] chore: move `gnoland genesis` to `contribs/gnogenesis` (#3041) ## Description This PR migrates the `gnoland genesis` command suite under `contribs/gnogenesis`, after following discussions from #2824, and internal discussions. **BREAKING CHANGE** `gnoland genesis` will cease to exist after this PR, instead, you will need to use the binary in `contribs/gnogenesis`. It's installed by default after running `make install` from the repo root. Closes #2824
    Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
    --- Makefile | 7 +- contribs/gnogenesis/Makefile | 18 ++ contribs/gnogenesis/README.md | 181 ++++++++++++++ contribs/gnogenesis/genesis.go | 32 +++ contribs/gnogenesis/go.mod | 62 +++++ contribs/gnogenesis/go.sum | 230 ++++++++++++++++++ .../gnogenesis/internal/balances/balances.go | 13 +- .../internal/balances/balances_add.go | 6 +- .../internal/balances/balances_add_test.go | 59 ++--- .../internal/balances/balances_export.go | 9 +- .../internal/balances/balances_export_test.go | 33 +-- .../internal/balances/balances_remove.go | 16 +- .../internal/balances/balances_remove_test.go | 35 ++- contribs/gnogenesis/internal/common/config.go | 35 +++ contribs/gnogenesis/internal/common/errors.go | 9 + .../gnogenesis/internal/common/helpers.go | 52 ++++ .../gnogenesis/internal/generate/generate.go | 24 +- .../internal/generate/generate_test.go | 33 +-- .../gnogenesis/internal/txs/txs.go | 45 +++- .../gnogenesis/internal/txs/txs_add.go | 2 +- .../internal/txs/txs_add_packages.go | 7 +- .../internal/txs/txs_add_packages_test.go | 21 +- .../gnogenesis/internal/txs/txs_add_sheet.go | 6 +- .../internal/txs/txs_add_sheet_test.go | 39 ++- .../gnogenesis/internal/txs/txs_export.go | 10 +- .../internal/txs/txs_export_test.go | 29 +-- .../gnogenesis/internal/txs/txs_list.go | 7 +- .../gnogenesis/internal/txs/txs_list_test.go | 15 +- .../gnogenesis/internal/txs/txs_remove.go | 6 +- .../internal/txs/txs_remove_test.go | 27 +- .../internal/validator/validator.go | 15 +- .../internal/validator/validator_add.go | 6 +- .../internal/validator/validator_add_test.go | 107 ++------ .../internal/validator/validator_remove.go | 6 +- .../validator/validator_remove_test.go | 31 +-- .../gnogenesis/internal/verify/verify.go | 17 +- .../gnogenesis/internal/verify/verify_test.go | 22 +- contribs/gnogenesis/main.go | 14 ++ docs/gno-infrastructure/validators/faq.md | 35 --- .../validators/setting-up-a-new-chain.md | 15 +- docs/gno-tooling/cli/gnoland.md | 158 ------------ gno.land/cmd/gnoland/genesis.go | 46 ---- gno.land/cmd/gnoland/root.go | 1 - gno.land/cmd/gnoland/start.go | 8 + gno.land/cmd/gnoland/types.go | 37 --- 45 files changed, 916 insertions(+), 670 deletions(-) create mode 100644 contribs/gnogenesis/Makefile create mode 100644 contribs/gnogenesis/README.md create mode 100644 contribs/gnogenesis/genesis.go create mode 100644 contribs/gnogenesis/go.mod create mode 100644 contribs/gnogenesis/go.sum rename gno.land/cmd/gnoland/genesis_balances.go => contribs/gnogenesis/internal/balances/balances.go (68%) rename gno.land/cmd/gnoland/genesis_balances_add.go => contribs/gnogenesis/internal/balances/balances_add.go (98%) rename gno.land/cmd/gnoland/genesis_balances_add_test.go => contribs/gnogenesis/internal/balances/balances_add_test.go (92%) rename gno.land/cmd/gnoland/genesis_balances_export.go => contribs/gnogenesis/internal/balances/balances_export.go (89%) rename gno.land/cmd/gnoland/genesis_balances_export_test.go => contribs/gnogenesis/internal/balances/balances_export_test.go (83%) rename gno.land/cmd/gnoland/genesis_balances_remove.go => contribs/gnogenesis/internal/balances/balances_remove.go (84%) rename gno.land/cmd/gnoland/genesis_balances_remove_test.go => contribs/gnogenesis/internal/balances/balances_remove_test.go (81%) create mode 100644 contribs/gnogenesis/internal/common/config.go create mode 100644 contribs/gnogenesis/internal/common/errors.go create mode 100644 contribs/gnogenesis/internal/common/helpers.go rename gno.land/cmd/gnoland/genesis_generate.go => contribs/gnogenesis/internal/generate/generate.go (85%) rename gno.land/cmd/gnoland/genesis_generate_test.go => contribs/gnogenesis/internal/generate/generate_test.go (89%) rename gno.land/cmd/gnoland/genesis_txs.go => contribs/gnogenesis/internal/txs/txs.go (65%) rename gno.land/cmd/gnoland/genesis_txs_add.go => contribs/gnogenesis/internal/txs/txs_add.go (97%) rename gno.land/cmd/gnoland/genesis_txs_add_packages.go => contribs/gnogenesis/internal/txs/txs_add_packages.go (92%) rename gno.land/cmd/gnoland/genesis_txs_add_packages_test.go => contribs/gnogenesis/internal/txs/txs_add_packages_test.go (88%) rename gno.land/cmd/gnoland/genesis_txs_add_sheet.go => contribs/gnogenesis/internal/txs/txs_add_sheet.go (93%) rename gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go => contribs/gnogenesis/internal/txs/txs_add_sheet_test.go (89%) rename gno.land/cmd/gnoland/genesis_txs_export.go => contribs/gnogenesis/internal/txs/txs_export.go (92%) rename gno.land/cmd/gnoland/genesis_txs_export_test.go => contribs/gnogenesis/internal/txs/txs_export_test.go (84%) rename gno.land/cmd/gnoland/genesis_txs_list.go => contribs/gnogenesis/internal/txs/txs_list.go (86%) rename gno.land/cmd/gnoland/genesis_txs_list_test.go => contribs/gnogenesis/internal/txs/txs_list_test.go (83%) rename gno.land/cmd/gnoland/genesis_txs_remove.go => contribs/gnogenesis/internal/txs/txs_remove.go (94%) rename gno.land/cmd/gnoland/genesis_txs_remove_test.go => contribs/gnogenesis/internal/txs/txs_remove_test.go (86%) rename gno.land/cmd/gnoland/genesis_validator.go => contribs/gnogenesis/internal/validator/validator.go (68%) rename gno.land/cmd/gnoland/genesis_validator_add.go => contribs/gnogenesis/internal/validator/validator_add.go (95%) rename gno.land/cmd/gnoland/genesis_validator_add_test.go => contribs/gnogenesis/internal/validator/validator_add_test.go (66%) rename gno.land/cmd/gnoland/genesis_validator_remove.go => contribs/gnogenesis/internal/validator/validator_remove.go (92%) rename gno.land/cmd/gnoland/genesis_validator_remove_test.go => contribs/gnogenesis/internal/validator/validator_remove_test.go (81%) rename gno.land/cmd/gnoland/genesis_verify.go => contribs/gnogenesis/internal/verify/verify.go (80%) rename gno.land/cmd/gnoland/genesis_verify_test.go => contribs/gnogenesis/internal/verify/verify_test.go (90%) create mode 100644 contribs/gnogenesis/main.go delete mode 100644 gno.land/cmd/gnoland/genesis.go delete mode 100644 gno.land/cmd/gnoland/types.go diff --git a/Makefile b/Makefile index fe862d52893..5cf8c8c58f9 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ VERIFY_MOD_SUMS ?= false ######################################## # Dev tools .PHONY: install -install: install.gnokey install.gno install.gnodev +install: install.gnokey install.gno install.gnodev install.gnogenesis # shortcuts to frequently used commands from sub-components. .PHONY: install.gnokey @@ -45,6 +45,11 @@ install.gno: install.gnodev: $(MAKE) --no-print-directory -C ./contribs/gnodev install @printf "\033[0;32m[+] 'gnodev' has been installed. Read more in ./contribs/gnodev/\033[0m\n" +.PHONY: install.gnogenesis +install.gnogenesis: + $(MAKE) --no-print-directory -C ./contribs/gnogenesis install + @printf "\033[0;32m[+] 'gnogenesis' has been installed. Read more in ./contribs/gnogenesis/\033[0m\n" + # old aliases .PHONY: install_gnokey diff --git a/contribs/gnogenesis/Makefile b/contribs/gnogenesis/Makefile new file mode 100644 index 00000000000..20f234e7e36 --- /dev/null +++ b/contribs/gnogenesis/Makefile @@ -0,0 +1,18 @@ +rundep := go run -modfile ../../misc/devdeps/go.mod +golangci_lint := $(rundep) github.com/golangci/golangci-lint/cmd/golangci-lint + + +.PHONY: install +install: + go install . + +.PHONY: build +build: + go build -o build/gnogenesis . + +lint: + $(golangci_lint) --config ../../.github/golangci.yml run ./... + +test: + go test $(GOTEST_FLAGS) -v ./... + diff --git a/contribs/gnogenesis/README.md b/contribs/gnogenesis/README.md new file mode 100644 index 00000000000..ae8daa6b81c --- /dev/null +++ b/contribs/gnogenesis/README.md @@ -0,0 +1,181 @@ +## Overview + +`gnogenesis` is a CLI tool for managing the Gnoland blockchain's `genesis.json` file. It provides +subcommands for setting up and manipulating the genesis file, from generating a new genesis configuration to managing +initial validators, balances, and transactions. + +Refer to specific command help options (`--help`) for further customization options. + +## Installation + +To install gnogenesis, clone the repository and build the tool: + +```shell +git clone https://github.com/gnoland/gno.git +cd gno +make install.gnogenesis +``` + +This will compile and install `gnogenesis` to your system path, allowing you to run commands directly. + +## Features + +### Generate a `genesis.json` + +To create a new genesis.json, use the `generate` subcommand. You can specify parameters such as chain ID, block limits, +and more: + +```shell +gnogenesis generate --chain-id gno-dev --block-max-gas 100000000 --output-path ./genesis.json +``` + +This command generates a genesis.json file with custom parameters, defining the chain’s identity, block limits, and +more. By default, the genesis-time is set to the current timestamp, or you can specify a future time for scheduled chain +launches. + +Keep in mind the `genesis.json` is generated with an empty validator set, and you will need to manually add the initial +validators. + +### Manage initial validators + +The `validator` subcommands allow you to add or remove validators directly in the genesis file. + +#### Add a validator + +To add a validator, specify their `address`, `name`, and `pub-key`: + +```shell +gnogenesis validator add --address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h --name validator1 --pub-key gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zplmcmggxyxyrch0zcyg684yxmerullv3l6hmau58sk4eyxskmny9h7lsnz +``` + +This command will add the validator with the specified details in the genesis file. + +The `address` and `pub-key` values need to be in bech32 format. They can be fetched using `gnoland secrets get`. + +#### Remove a validator + +If you need to remove a validator, specify their address: + +```shell +gnogenesis validator remove --address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h +``` + +This will remove the specified validator from the validator set in `genesis.json`, if it is present. + +### Verify the `genesis.json` + +The `verify` subcommand is helpful to confirm the integrity of a `genesis.json` file: + +```shell +gnogenesis verify --genesis-path ./genesis.json +``` + +This validation checks for proper structure, account balance totals, and ensures validators are correctly configured, +preventing common genesis setup issues. It is advised to always run this verification step when dealing with an external +`genesis.json`. + +### Manage account balances + +Balances can be added or removed through the balances subcommand, either individually or using a balance sheet file. + +The format for individual balance entries is `
    =ugnot`. + +#### Add Account Balances + +Add a single balance directly: + +```shell +gnogenesis balances add --single g1rzuwh5frve732k4futyw45y78rzuty4626zy6h=100ugnot +``` + +Alternatively, load multiple accounts with a balance sheet file: + +```shell +gnogenesis balances add --balance-sheet ./balances.txt +``` + +The format of the balance sheet file is the same as with individual entries, for example: + +```text +# Test accounts. +g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5=10000000000000ugnot # test1 +g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj=10000000000000ugnot # test2 + +# Faucet accounts. +g1f4v282mwyhu29afke4vq5r2xzcm6z3ftnugcnv=1000000000000ugnot # faucet0 (jae) +g127jydsh6cms3lrtdenydxsckh23a8d6emqcvfa=1000000000000ugnot # faucet1 (moul) +g1q6jrp203fq0239pv38sdq3y3urvd6vt5azacpv=1000000000000ugnot # faucet2 (devx) +g13d7jc32adhc39erm5me38w5v7ej7lpvlnqjk73=1000000000000ugnot # faucet3 (devx) +g18l9us6trqaljw39j94wzf5ftxmd9qqkvrxghd2=1000000000000ugnot # faucet4 (adena) +``` + +This will update `genesis.json` with the provided accounts and balances. + +#### Remove account balances + +To remove an account’s balance from `genesis.json`, use: + +```shell +gnogenesis balances remove --address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h +``` + +This deletes the balance entry for the specified address, if present. + +### Handle genesis transactions + +The `txs` subcommand allows you to manage initial transactions. + +It is a bit more robust than the `balances` command suite, in the sense that it supports: + +- adding transactions from transaction sheets +- generating and adding deploy transactions from a directory (ex. like `examples`) + +The format for transactions in the transaction sheet is the following: + +- Transaction (`std.Tx`) is encoded in Amino JSON +- Transactions are saved single-line, 1 line 1 tx +- File format of the transaction sheet file is `jsonl` + +#### Add genesis transactions + +To add genesis transactions from a file: + +```shell +gnogenesis txs add sheets ./txs.json +``` + +This outputs the initial transaction count. + +An example transaction sheet: + +```json lines +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj:10\ng1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s:1\ng13sm84nuqed3fuank8huh7x9mupgw22uft3lcl8:1\ng1m6732pkrngu9vrt0g7056lvr9kcqc4mv83xl5q:1\ng1wg88rhzlwxjd2z4j5de5v5xq30dcf6rjq3dhsj:1\ng18pmaskasz7mxj6rmgrl3al58xu45a7w0l5nmc0:1\ng19wwhkmqlns70604ksp6rkuuu42qhtvyh05lffz:1\ng187982000zsc493znqt828s90cmp6hcp2erhu6m:1\ng1ndpsnrspdnauckytvkfv8s823t3gmpqmtky8pl:1\ng16ja66d65emkr0zxd2tu7xjvm7utthyhpej0037:1\ng1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5:1\ng1trkzq75ntamsnw9xnrav2v7gy2lt5g6p29yhdr:1\ng1rrf8s5mrmu00sx04fzfsvc399fklpeg2x0a7mz:1\ng19p5ntfvpt4lwq4jqsmnxsnelhf3tff9scy3w8w:1\ng1tue8l73d6rq4vhqdsp2sr3zhuzpure3k2rnwpz:1\ng14hhsss4ngx5kq77je5g0tl4vftg8qp45ceadk3:1\ng1768hvkh7anhd40ch4h7jdh6j3mpcs7hrat4gl0:1\ng15fa8kyjhu88t9dr8zzua8fwdvkngv5n8yqsm0n:1\ng1xhccdjcscuhgmt3quww6qdy3j3czqt3urc2eac:1\ng1z629z04f85k4t5gnkk5egpxw9tqxeec435esap:1\ng1pfldkplz9puq0v82lu9vqcve9nwrxuq9qe5ttv:1\ng152pn0g5qfgxr7yx8zlwjq48hytkafd8x7egsfv:1\ng1cf2ye686ke38vjyqakreprljum4xu6rwf5jskq:1\ng1c5shztyaj4gjrc5zlwmh9xhex5w7l4asffs2w6:1\ng1lhpx2ktk0ha3qw42raxq4m24a4c4xqxyrgv54q:1\ng1026p54q0j902059sm2zsv37krf0ghcl7gmhyv7:1\ng1n4yvwnv77frq2ccuw27dmtjkd7u4p4jg0pgm7k:1\ng13m7f2e6r3lh3ykxupacdt9sem2tlvmaamwjhll:1\ng19uxluuecjlsqvwmwu8sp6pxaaqfhk972q975xd:1\ng1j80fpcsumfkxypvydvtwtz3j4sdwr8c2u0lr64:1\ng1tjdpptuk9eysq6z38nscqyycr998xjyx3w8jvw:1\ng19t3n89slfemgd3mwuat4lajwcp0yxrkadgeg7a:1\ng1yqndt8xx92l9h494jfruz2w79swzjes3n4wqjc:1\ng13278z0a5ufeg80ffqxpda9dlp599t7ekregcy6:1\ng1ht236wjd83x96uqwh9rh3fq6pylyn78mtwq9v6:1\ng1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9:1\ng1wwppuzdns5u6c6jqpkzua24zh6ppsus6399cea:1\ng1k8pjnguyu36pkc8hy0ufzgpzfmj2jl78la7ek3:1\ng1e8umkzumtxgs8399lw0us4rclea3xl5gxy9spp:1\ng14qekdkj2nmmwea4ufg9n002a3pud23y8k7ugs5:1\ng19w2488ntfgpduzqq3sk4j5x387zynwknqdvjqf:1\ng1495y3z7zrej4rendysnw5kaeu4g3d7x7w0734g:1\ng1hygx8ga9qakhkczyrzs9drm8j8tu4qds9y5e3r:1\ng1f977l6wxdh3qu60kzl75vx2wmzswu68l03r8su:1\ng1644qje5rx6jsdqfkzmgnfcegx4dxkjh6rwqd69:1\ng1mzjajymvmtksdwh3wkrndwj6zls2awl9q83dh6:1\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa:10\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t:5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"S8iMMzlOMK8dmox78R9Z8+pSsS8YaTCXrIcaHDpiOgkOy7gqoQJ0oftM0zf8zAz4xpezK8Lzg8Q0fCdXJxV76w=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1thlf3yct7n7ex70k0p62user0kn6mj6d3s0cg3\ng1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"njczE6xYdp01+CaUU/8/v0YC/NuZD06+qLind+ZZEEMNaRe/4Ln+4z7dG6HYlaWUMsyI1KCoB6NIehoE0PZ44Q=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/users","func":"Invite","args":["g1589c8cekvmjfmy0qrd4f3z52r7fn7rgk02667s\ng13sm84nuqed3fuank8huh7x9mupgw22uft3lcl8\ng1m6732pkrngu9vrt0g7056lvr9kcqc4mv83xl5q\ng1wg88rhzlwxjd2z4j5de5v5xq30dcf6rjq3dhsj\ng18pmaskasz7mxj6rmgrl3al58xu45a7w0l5nmc0\ng19wwhkmqlns70604ksp6rkuuu42qhtvyh05lffz\ng187982000zsc493znqt828s90cmp6hcp2erhu6m\ng1ndpsnrspdnauckytvkfv8s823t3gmpqmtky8pl\ng16ja66d65emkr0zxd2tu7xjvm7utthyhpej0037\ng1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5\ng1trkzq75ntamsnw9xnrav2v7gy2lt5g6p29yhdr\ng1rrf8s5mrmu00sx04fzfsvc399fklpeg2x0a7mz\ng19p5ntfvpt4lwq4jqsmnxsnelhf3tff9scy3w8w\ng1tue8l73d6rq4vhqdsp2sr3zhuzpure3k2rnwpz\ng14hhsss4ngx5kq77je5g0tl4vftg8qp45ceadk3\ng1768hvkh7anhd40ch4h7jdh6j3mpcs7hrat4gl0\ng15fa8kyjhu88t9dr8zzua8fwdvkngv5n8yqsm0n\ng1xhccdjcscuhgmt3quww6qdy3j3czqt3urc2eac\ng1z629z04f85k4t5gnkk5egpxw9tqxeec435esap\ng1pfldkplz9puq0v82lu9vqcve9nwrxuq9qe5ttv\ng152pn0g5qfgxr7yx8zlwjq48hytkafd8x7egsfv\ng1cf2ye686ke38vjyqakreprljum4xu6rwf5jskq\ng1c5shztyaj4gjrc5zlwmh9xhex5w7l4asffs2w6\ng1lhpx2ktk0ha3qw42raxq4m24a4c4xqxyrgv54q\ng1026p54q0j902059sm2zsv37krf0ghcl7gmhyv7\ng1n4yvwnv77frq2ccuw27dmtjkd7u4p4jg0pgm7k\ng13m7f2e6r3lh3ykxupacdt9sem2tlvmaamwjhll\ng19uxluuecjlsqvwmwu8sp6pxaaqfhk972q975xd\ng1j80fpcsumfkxypvydvtwtz3j4sdwr8c2u0lr64\ng1tjdpptuk9eysq6z38nscqyycr998xjyx3w8jvw\ng19t3n89slfemgd3mwuat4lajwcp0yxrkadgeg7a\ng1yqndt8xx92l9h494jfruz2w79swzjes3n4wqjc\ng13278z0a5ufeg80ffqxpda9dlp599t7ekregcy6\ng1ht236wjd83x96uqwh9rh3fq6pylyn78mtwq9v6\ng1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9\ng1wwppuzdns5u6c6jqpkzua24zh6ppsus6399cea\ng1k8pjnguyu36pkc8hy0ufzgpzfmj2jl78la7ek3\ng1e8umkzumtxgs8399lw0us4rclea3xl5gxy9spp\ng14qekdkj2nmmwea4ufg9n002a3pud23y8k7ugs5\ng19w2488ntfgpduzqq3sk4j5x387zynwknqdvjqf\ng1495y3z7zrej4rendysnw5kaeu4g3d7x7w0734g\ng1hygx8ga9qakhkczyrzs9drm8j8tu4qds9y5e3r\ng1f977l6wxdh3qu60kzl75vx2wmzswu68l03r8su\ng1644qje5rx6jsdqfkzmgnfcegx4dxkjh6rwqd69\ng1mzjajymvmtksdwh3wkrndwj6zls2awl9q83dh6\ng1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq\ng14da4n9hcynyzz83q607uu8keuh9hwlv42ra6fa\ng14vhcdsyf83ngsrrqc92kmw8q9xakqjm0v8448t\n"]}],"fee":{"gas_wanted":"4000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"7AmlhZhsVkxCUl0bbpvpPMnIKihwtG7A5IFR6Tg4xStWLgaUr05XmWRKlO2xjstTtwbVKQT5mFL4h5wyX4SQzw=="}],"memo":""} +``` + +To add genesis (deploy) transactions from a directory: + +```shell +gnogenesis txs add packages ./examples +``` + +This will generate `MsgAddPkg` transactions, and add them to the given `genesis.json`. + +#### Remove genesis transactions + +To clear specific transactions, use the transaction hash: + +```shell +gnogenesis txs remove "5HuU9LN8WUa2NsjiNxp8Xii9n0zlSGXc9UqzLHB+DPs=" +``` + +The transaction hash is the base64 encoding of the Amino-Binary encoded `std.Tx` transaction hash. + +The steps to get this sort of hash are: + +- get the `std.Tx` +- marshal it using `amino.Marshal` +- cast the result to `types.Tx` (`bft`) +- call `Hash` on the `types.Tx` +- encode the result into base64 diff --git a/contribs/gnogenesis/genesis.go b/contribs/gnogenesis/genesis.go new file mode 100644 index 00000000000..839e5fbe653 --- /dev/null +++ b/contribs/gnogenesis/genesis.go @@ -0,0 +1,32 @@ +package main + +import ( + "github.com/gnolang/contribs/gnogenesis/internal/balances" + "github.com/gnolang/contribs/gnogenesis/internal/generate" + "github.com/gnolang/contribs/gnogenesis/internal/txs" + "github.com/gnolang/contribs/gnogenesis/internal/validator" + "github.com/gnolang/contribs/gnogenesis/internal/verify" + "github.com/gnolang/gno/tm2/pkg/commands" +) + +func newGenesisCmd(io commands.IO) *commands.Command { + cmd := commands.NewCommand( + commands.Metadata{ + ShortUsage: " [flags] [...]", + ShortHelp: "gno genesis manipulation suite", + LongHelp: "Gno genesis.json manipulation suite, for managing genesis parameters", + }, + commands.NewEmptyConfig(), + commands.HelpExec, + ) + + cmd.AddSubCommands( + generate.NewGenerateCmd(io), + validator.NewValidatorCmd(io), + verify.NewVerifyCmd(io), + balances.NewBalancesCmd(io), + txs.NewTxsCmd(io), + ) + + return cmd +} diff --git a/contribs/gnogenesis/go.mod b/contribs/gnogenesis/go.mod new file mode 100644 index 00000000000..cdd8922fad5 --- /dev/null +++ b/contribs/gnogenesis/go.mod @@ -0,0 +1,62 @@ +module github.com/gnolang/contribs/gnogenesis + +go 1.22 + +require ( + github.com/gnolang/gno v0.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.9.0 +) + +replace github.com/gnolang/gno => ../.. + +require ( + dario.cat/mergo v1.0.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // 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 + 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-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + 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/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.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/cors v1.11.1 // indirect + github.com/rs/xid v1.6.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.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.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/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 + 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 + 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/gnogenesis/go.sum b/contribs/gnogenesis/go.sum new file mode 100644 index 00000000000..28c509e381e --- /dev/null +++ b/contribs/gnogenesis/go.sum @@ -0,0 +1,230 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/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/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/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= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +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/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/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= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +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/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= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +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-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/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= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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.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/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= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +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/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/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/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= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= +github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +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/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/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/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.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= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +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/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/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/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/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= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +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/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/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/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/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= +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= +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= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gno.land/cmd/gnoland/genesis_balances.go b/contribs/gnogenesis/internal/balances/balances.go similarity index 68% rename from gno.land/cmd/gnoland/genesis_balances.go rename to contribs/gnogenesis/internal/balances/balances.go index c8cd1c539f5..bdfa5aa38d0 100644 --- a/gno.land/cmd/gnoland/genesis_balances.go +++ b/contribs/gnogenesis/internal/balances/balances.go @@ -1,23 +1,24 @@ -package main +package balances import ( "flag" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/tm2/pkg/commands" ) type balancesCfg struct { - commonCfg + common.Cfg } -// newBalancesCmd creates the genesis balances subcommand -func newBalancesCmd(io commands.IO) *commands.Command { +// NewBalancesCmd creates the genesis balances subcommand +func NewBalancesCmd(io commands.IO) *commands.Command { cfg := &balancesCfg{} cmd := commands.NewCommand( commands.Metadata{ Name: "balances", - ShortUsage: "balances [flags]", + ShortUsage: " [flags]", ShortHelp: "manages genesis.json account balances", LongHelp: "Manipulates the initial genesis.json account balances (pre-mines)", }, @@ -35,5 +36,5 @@ func newBalancesCmd(io commands.IO) *commands.Command { } func (c *balancesCfg) RegisterFlags(fs *flag.FlagSet) { - c.commonCfg.RegisterFlags(fs) + c.Cfg.RegisterFlags(fs) } diff --git a/gno.land/cmd/gnoland/genesis_balances_add.go b/contribs/gnogenesis/internal/balances/balances_add.go similarity index 98% rename from gno.land/cmd/gnoland/genesis_balances_add.go rename to contribs/gnogenesis/internal/balances/balances_add.go index f9a898715c8..a17a13f8bc8 100644 --- a/gno.land/cmd/gnoland/genesis_balances_add.go +++ b/contribs/gnogenesis/internal/balances/balances_add.go @@ -1,4 +1,4 @@ -package main +package balances import ( "bufio" @@ -77,7 +77,7 @@ func (c *balancesAddCfg) RegisterFlags(fs *flag.FlagSet) { func execBalancesAdd(ctx context.Context, cfg *balancesAddCfg, io commands.IO) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -156,7 +156,7 @@ func execBalancesAdd(ctx context.Context, cfg *balancesAddCfg, io commands.IO) e genesis.AppState = state // Save the updated genesis - if err := genesis.SaveAs(cfg.rootCfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.rootCfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_balances_add_test.go b/contribs/gnogenesis/internal/balances/balances_add_test.go similarity index 92% rename from gno.land/cmd/gnoland/genesis_balances_add_test.go rename to contribs/gnogenesis/internal/balances/balances_add_test.go index 8f2879f9c57..29ffe19d95a 100644 --- a/gno.land/cmd/gnoland/genesis_balances_add_test.go +++ b/contribs/gnogenesis/internal/balances/balances_add_test.go @@ -1,4 +1,4 @@ -package main +package balances import ( "bytes" @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" @@ -24,10 +25,8 @@ func TestGenesis_Balances_Add(t *testing.T) { t.Run("invalid genesis", func(t *testing.T) { // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", "dummy-path", @@ -35,7 +34,7 @@ func TestGenesis_Balances_Add(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - require.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + require.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("no sources selected", func(t *testing.T) { @@ -44,14 +43,12 @@ func TestGenesis_Balances_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", tempGenesis.Name(), @@ -66,10 +63,8 @@ func TestGenesis_Balances_Add(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", "dummy-path", @@ -77,25 +72,23 @@ func TestGenesis_Balances_Add(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("balances from entries", func(t *testing.T) { t.Parallel() - dummyKeys := getDummyKeys(t, 2) + dummyKeys := common.GetDummyKeys(t, 2) tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", tempGenesis.Name(), @@ -155,10 +148,10 @@ func TestGenesis_Balances_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) - dummyKeys := getDummyKeys(t, 10) + dummyKeys := common.GetDummyKeys(t, 10) amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) balances := make([]string, len(dummyKeys)) @@ -182,10 +175,8 @@ func TestGenesis_Balances_Add(t *testing.T) { require.NoError(t, err) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", tempGenesis.Name(), @@ -233,11 +224,11 @@ func TestGenesis_Balances_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) var ( - dummyKeys = getDummyKeys(t, 10) + dummyKeys = common.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) @@ -282,10 +273,8 @@ func TestGenesis_Balances_Add(t *testing.T) { require.NoError(t, err) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", tempGenesis.Name(), @@ -337,12 +326,12 @@ func TestGenesis_Balances_Add(t *testing.T) { t.Run("balances overwrite", func(t *testing.T) { t.Parallel() - dummyKeys := getDummyKeys(t, 10) + dummyKeys := common.GetDummyKeys(t, 10) tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() state := gnoland.GnoGenesisState{ // Set an initial balance value Balances: []gnoland.Balance{ @@ -356,10 +345,8 @@ func TestGenesis_Balances_Add(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "add", "--genesis-path", tempGenesis.Name(), @@ -421,7 +408,7 @@ func TestBalances_GetBalancesFromTransactions(t *testing.T) { t.Parallel() var ( - dummyKeys = getDummyKeys(t, 10) + dummyKeys = common.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) @@ -479,7 +466,7 @@ func TestBalances_GetBalancesFromTransactions(t *testing.T) { t.Parallel() var ( - dummyKeys = getDummyKeys(t, 10) + dummyKeys = common.GetDummyKeys(t, 10) amountCoins = std.NewCoins(std.NewCoin(ugnot.Denom, 10)) gasFee = std.NewCoin("gnos", 1) // invalid fee txs = make([]std.Tx, 0) @@ -531,7 +518,7 @@ func TestBalances_GetBalancesFromTransactions(t *testing.T) { t.Parallel() var ( - dummyKeys = getDummyKeys(t, 10) + dummyKeys = common.GetDummyKeys(t, 10) amountCoins = std.NewCoins(std.NewCoin("gnogno", 10)) // invalid send amount gasFee = std.NewCoin(ugnot.Denom, 1) txs = make([]std.Tx, 0) diff --git a/gno.land/cmd/gnoland/genesis_balances_export.go b/contribs/gnogenesis/internal/balances/balances_export.go similarity index 89% rename from gno.land/cmd/gnoland/genesis_balances_export.go rename to contribs/gnogenesis/internal/balances/balances_export.go index ec05d115b97..df9d6795805 100644 --- a/gno.land/cmd/gnoland/genesis_balances_export.go +++ b/contribs/gnogenesis/internal/balances/balances_export.go @@ -1,10 +1,11 @@ -package main +package balances import ( "context" "fmt" "os" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -28,14 +29,14 @@ func newBalancesExportCmd(balancesCfg *balancesCfg, io commands.IO) *commands.Co func execBalancesExport(cfg *balancesCfg, io commands.IO, args []string) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } // Load the genesis state if genesis.AppState == nil { - return errAppStateNotSet + return common.ErrAppStateNotSet } state := genesis.AppState.(gnoland.GnoGenesisState) @@ -47,7 +48,7 @@ func execBalancesExport(cfg *balancesCfg, io commands.IO, args []string) error { // Make sure the output file path is specified if len(args) == 0 { - return errNoOutputFile + return common.ErrNoOutputFile } // Open output file diff --git a/gno.land/cmd/gnoland/genesis_balances_export_test.go b/contribs/gnogenesis/internal/balances/balances_export_test.go similarity index 83% rename from gno.land/cmd/gnoland/genesis_balances_export_test.go rename to contribs/gnogenesis/internal/balances/balances_export_test.go index bd1f6152246..d4f4723df15 100644 --- a/gno.land/cmd/gnoland/genesis_balances_export_test.go +++ b/contribs/gnogenesis/internal/balances/balances_export_test.go @@ -1,10 +1,11 @@ -package main +package balances import ( "bufio" "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/commands" @@ -18,7 +19,7 @@ import ( func getDummyBalances(t *testing.T, count int) []gnoland.Balance { t.Helper() - dummyKeys := getDummyKeys(t, count) + dummyKeys := common.GetDummyKeys(t, count) amount := std.NewCoins(std.NewCoin(ugnot.Denom, 10)) balances := make([]gnoland.Balance, len(dummyKeys)) @@ -40,10 +41,8 @@ func TestGenesis_Balances_Export(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "export", "--genesis-path", "dummy-path", @@ -51,7 +50,7 @@ func TestGenesis_Balances_Export(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid genesis app state", func(t *testing.T) { @@ -60,15 +59,13 @@ func TestGenesis_Balances_Export(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = nil // no app state require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "export", "--genesis-path", tempGenesis.Name(), @@ -76,7 +73,7 @@ func TestGenesis_Balances_Export(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errAppStateNotSet.Error()) + assert.ErrorContains(t, cmdErr, common.ErrAppStateNotSet.Error()) }) t.Run("no output file specified", func(t *testing.T) { @@ -85,17 +82,15 @@ func TestGenesis_Balances_Export(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Balances: getDummyBalances(t, 1), } require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "export", "--genesis-path", tempGenesis.Name(), @@ -103,7 +98,7 @@ func TestGenesis_Balances_Export(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errNoOutputFile.Error()) + assert.ErrorContains(t, cmdErr, common.ErrNoOutputFile.Error()) }) t.Run("valid balances export", func(t *testing.T) { @@ -115,7 +110,7 @@ func TestGenesis_Balances_Export(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Balances: balances, } @@ -126,10 +121,8 @@ func TestGenesis_Balances_Export(t *testing.T) { t.Cleanup(outputCleanup) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "export", "--genesis-path", tempGenesis.Name(), diff --git a/gno.land/cmd/gnoland/genesis_balances_remove.go b/contribs/gnogenesis/internal/balances/balances_remove.go similarity index 84% rename from gno.land/cmd/gnoland/genesis_balances_remove.go rename to contribs/gnogenesis/internal/balances/balances_remove.go index 58a02319c8d..ea2aefda5cc 100644 --- a/gno.land/cmd/gnoland/genesis_balances_remove.go +++ b/contribs/gnogenesis/internal/balances/balances_remove.go @@ -1,4 +1,4 @@ -package main +package balances import ( "context" @@ -6,16 +6,14 @@ import ( "flag" "fmt" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto" ) -var ( - errUnableToLoadGenesis = errors.New("unable to load genesis") - errBalanceNotFound = errors.New("genesis balances entry does not exist") -) +var errBalanceNotFound = errors.New("genesis balances entry does not exist") type balancesRemoveCfg struct { rootCfg *balancesCfg @@ -53,9 +51,9 @@ func (c *balancesRemoveCfg) RegisterFlags(fs *flag.FlagSet) { func execBalancesRemove(cfg *balancesRemoveCfg, io commands.IO) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.GenesisPath) if loadErr != nil { - return fmt.Errorf("%w, %w", errUnableToLoadGenesis, loadErr) + return fmt.Errorf("%w, %w", common.ErrUnableToLoadGenesis, loadErr) } // Validate the address @@ -66,7 +64,7 @@ func execBalancesRemove(cfg *balancesRemoveCfg, io commands.IO) error { // Check if the genesis state is set at all if genesis.AppState == nil { - return errAppStateNotSet + return common.ErrAppStateNotSet } // Construct the initial genesis balance sheet @@ -90,7 +88,7 @@ func execBalancesRemove(cfg *balancesRemoveCfg, io commands.IO) error { genesis.AppState = state // Save the updated genesis - if err := genesis.SaveAs(cfg.rootCfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.rootCfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_balances_remove_test.go b/contribs/gnogenesis/internal/balances/balances_remove_test.go similarity index 81% rename from gno.land/cmd/gnoland/genesis_balances_remove_test.go rename to contribs/gnogenesis/internal/balances/balances_remove_test.go index ed11836ba4d..ab99a31c0a9 100644 --- a/gno.land/cmd/gnoland/genesis_balances_remove_test.go +++ b/contribs/gnogenesis/internal/balances/balances_remove_test.go @@ -1,9 +1,10 @@ -package main +package balances import ( "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "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" @@ -19,10 +20,8 @@ func TestGenesis_Balances_Remove(t *testing.T) { t.Run("invalid genesis", func(t *testing.T) { // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "remove", "--genesis-path", "dummy-path", @@ -30,26 +29,24 @@ func TestGenesis_Balances_Remove(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - require.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + require.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("genesis app state not set", func(t *testing.T) { t.Parallel() - dummyKey := getDummyKey(t) + dummyKey := common.GetDummyKey(t) tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = nil // not set require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "remove", "--genesis-path", tempGenesis.Name(), @@ -59,18 +56,18 @@ func TestGenesis_Balances_Remove(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - require.ErrorContains(t, cmdErr, errAppStateNotSet.Error()) + require.ErrorContains(t, cmdErr, common.ErrAppStateNotSet.Error()) }) t.Run("address is present", func(t *testing.T) { t.Parallel() - dummyKey := getDummyKey(t) + dummyKey := common.GetDummyKey(t) tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() state := gnoland.GnoGenesisState{ // Set an initial balance value Balances: []gnoland.Balance{ @@ -84,10 +81,8 @@ func TestGenesis_Balances_Remove(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "remove", "--genesis-path", tempGenesis.Name(), @@ -114,12 +109,12 @@ func TestGenesis_Balances_Remove(t *testing.T) { t.Run("address not present", func(t *testing.T) { t.Parallel() - dummyKey := getDummyKey(t) + dummyKey := common.GetDummyKey(t) tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() state := gnoland.GnoGenesisState{ Balances: []gnoland.Balance{}, // Empty initial balance } @@ -127,10 +122,8 @@ func TestGenesis_Balances_Remove(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewBalancesCmd(commands.NewTestIO()) args := []string{ - "genesis", - "balances", "remove", "--genesis-path", tempGenesis.Name(), diff --git a/contribs/gnogenesis/internal/common/config.go b/contribs/gnogenesis/internal/common/config.go new file mode 100644 index 00000000000..99278b77764 --- /dev/null +++ b/contribs/gnogenesis/internal/common/config.go @@ -0,0 +1,35 @@ +package common + +import ( + "flag" + "time" + + "github.com/gnolang/gno/tm2/pkg/bft/types" +) + +const DefaultChainID = "dev" + +// Cfg is the common +// configuration for genesis commands +// that require a genesis.json +type Cfg struct { + GenesisPath string +} + +func (c *Cfg) RegisterFlags(fs *flag.FlagSet) { + fs.StringVar( + &c.GenesisPath, + "genesis-path", + "./genesis.json", + "the path to the genesis.json", + ) +} + +// GetDefaultGenesis returns the default genesis config +func GetDefaultGenesis() *types.GenesisDoc { + return &types.GenesisDoc{ + GenesisTime: time.Now(), + ChainID: DefaultChainID, + ConsensusParams: types.DefaultConsensusParams(), + } +} diff --git a/contribs/gnogenesis/internal/common/errors.go b/contribs/gnogenesis/internal/common/errors.go new file mode 100644 index 00000000000..6eff43e9dc7 --- /dev/null +++ b/contribs/gnogenesis/internal/common/errors.go @@ -0,0 +1,9 @@ +package common + +import "errors" + +var ( + ErrAppStateNotSet = errors.New("genesis app state not set") + ErrNoOutputFile = errors.New("no output file path specified") + ErrUnableToLoadGenesis = errors.New("unable to load genesis") +) diff --git a/contribs/gnogenesis/internal/common/helpers.go b/contribs/gnogenesis/internal/common/helpers.go new file mode 100644 index 00000000000..2b1f473aed1 --- /dev/null +++ b/contribs/gnogenesis/internal/common/helpers.go @@ -0,0 +1,52 @@ +package common + +import ( + "testing" + + "github.com/gnolang/gno/tm2/pkg/crypto" + "github.com/gnolang/gno/tm2/pkg/crypto/bip39" + "github.com/gnolang/gno/tm2/pkg/crypto/hd" + "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" + "github.com/gnolang/gno/tm2/pkg/crypto/secp256k1" + "github.com/stretchr/testify/require" +) + +// GetDummyKey generates a random public key, +// and returns the key info +func GetDummyKey(t *testing.T) crypto.PubKey { + t.Helper() + + mnemonic, err := client.GenerateMnemonic(256) + require.NoError(t, err) + + seed := bip39.NewSeed(mnemonic, "") + + return generateKeyFromSeed(seed, 0).PubKey() +} + +// generateKeyFromSeed generates a private key from +// the provided seed and index +func generateKeyFromSeed(seed []byte, index uint32) crypto.PrivKey { + pathParams := hd.NewFundraiserParams(0, crypto.CoinType, index) + + masterPriv, ch := hd.ComputeMastersFromSeed(seed) + + //nolint:errcheck // This derivation can never error out, since the path params + // are always going to be valid + derivedPriv, _ := hd.DerivePrivateKeyForPath(masterPriv, ch, pathParams.String()) + + return secp256k1.PrivKeySecp256k1(derivedPriv) +} + +// GetDummyKeys generates random keys for testing +func GetDummyKeys(t *testing.T, count int) []crypto.PubKey { + t.Helper() + + dummyKeys := make([]crypto.PubKey, count) + + for i := 0; i < count; i++ { + dummyKeys[i] = GetDummyKey(t) + } + + return dummyKeys +} diff --git a/gno.land/cmd/gnoland/genesis_generate.go b/contribs/gnogenesis/internal/generate/generate.go similarity index 85% rename from gno.land/cmd/gnoland/genesis_generate.go rename to contribs/gnogenesis/internal/generate/generate.go index 751ac14ae62..729b904d548 100644 --- a/gno.land/cmd/gnoland/genesis_generate.go +++ b/contribs/gnogenesis/internal/generate/generate.go @@ -1,4 +1,4 @@ -package main +package generate import ( "context" @@ -6,12 +6,11 @@ import ( "fmt" "time" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" ) -var defaultChainID = "dev" - type generateCfg struct { outputPath string chainID string @@ -22,14 +21,14 @@ type generateCfg struct { blockTimeIota int64 } -// newGenerateCmd creates the genesis generate subcommand -func newGenerateCmd(io commands.IO) *commands.Command { +// NewGenerateCmd creates the genesis generate subcommand +func NewGenerateCmd(io commands.IO) *commands.Command { cfg := &generateCfg{} return commands.NewCommand( commands.Metadata{ Name: "generate", - ShortUsage: "generate [flags]", + ShortUsage: "[flags]", ShortHelp: "generates a fresh genesis.json", LongHelp: "Generates a node's genesis.json based on specified parameters", }, @@ -58,7 +57,7 @@ func (c *generateCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( &c.chainID, "chain-id", - defaultChainID, + common.DefaultChainID, "the ID of the chain", ) @@ -93,7 +92,7 @@ func (c *generateCfg) RegisterFlags(fs *flag.FlagSet) { func execGenerate(cfg *generateCfg, io commands.IO) error { // Start with the default configuration - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() // Set the genesis time if cfg.genesisTime > 0 { @@ -142,12 +141,3 @@ func execGenerate(cfg *generateCfg, io commands.IO) error { return nil } - -// getDefaultGenesis returns the default genesis config -func getDefaultGenesis() *types.GenesisDoc { - return &types.GenesisDoc{ - GenesisTime: time.Now(), - ChainID: defaultChainID, - ConsensusParams: types.DefaultConsensusParams(), - } -} diff --git a/gno.land/cmd/gnoland/genesis_generate_test.go b/contribs/gnogenesis/internal/generate/generate_test.go similarity index 89% rename from gno.land/cmd/gnoland/genesis_generate_test.go rename to contribs/gnogenesis/internal/generate/generate_test.go index f078a161662..7ac02169d77 100644 --- a/gno.land/cmd/gnoland/genesis_generate_test.go +++ b/contribs/gnogenesis/internal/generate/generate_test.go @@ -1,4 +1,4 @@ -package main +package generate import ( "context" @@ -6,6 +6,7 @@ import ( "path/filepath" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/testutils" @@ -25,10 +26,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--output-path", genesisPath, } @@ -42,7 +41,7 @@ func TestGenesis_Generate(t *testing.T) { require.NoError(t, readErr) // Make sure the default configuration is set - defaultGenesis := getDefaultGenesis() + defaultGenesis := common.GetDefaultGenesis() defaultGenesis.GenesisTime = genesis.GenesisTime assert.Equal(t, defaultGenesis, genesis) @@ -59,10 +58,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--chain-id", chainID, "--output-path", @@ -91,10 +88,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--block-max-tx-bytes", fmt.Sprintf("%d", blockMaxTxBytes), "--output-path", @@ -127,10 +122,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--block-max-data-bytes", fmt.Sprintf("%d", blockMaxDataBytes), "--output-path", @@ -163,10 +156,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--block-max-gas", fmt.Sprintf("%d", blockMaxGas), "--output-path", @@ -199,10 +190,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--block-time-iota", fmt.Sprintf("%d", blockTimeIota), "--output-path", @@ -235,10 +224,8 @@ func TestGenesis_Generate(t *testing.T) { genesisPath := filepath.Join(tempDir, "genesis.json") // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewGenerateCmd(commands.NewTestIO()) args := []string{ - "genesis", - "generate", "--chain-id", invalidChainID, "--output-path", diff --git a/gno.land/cmd/gnoland/genesis_txs.go b/contribs/gnogenesis/internal/txs/txs.go similarity index 65% rename from gno.land/cmd/gnoland/genesis_txs.go rename to contribs/gnogenesis/internal/txs/txs.go index 46b8d1bd29c..f8a14eafefc 100644 --- a/gno.land/cmd/gnoland/genesis_txs.go +++ b/contribs/gnogenesis/internal/txs/txs.go @@ -1,9 +1,10 @@ -package main +package txs import ( "errors" "flag" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -11,19 +12,19 @@ import ( ) type txsCfg struct { - commonCfg + common.Cfg } var errInvalidGenesisStateType = errors.New("invalid genesis state type") -// newTxsCmd creates the genesis txs subcommand -func newTxsCmd(io commands.IO) *commands.Command { +// NewTxsCmd creates the genesis txs subcommand +func NewTxsCmd(io commands.IO) *commands.Command { cfg := &txsCfg{} cmd := commands.NewCommand( commands.Metadata{ Name: "txs", - ShortUsage: "txs [flags]", + ShortUsage: " [flags]", ShortHelp: "manages the initial genesis transactions", LongHelp: "Manages genesis transactions through input files", }, @@ -42,7 +43,7 @@ func newTxsCmd(io commands.IO) *commands.Command { } func (c *txsCfg) RegisterFlags(fs *flag.FlagSet) { - c.commonCfg.RegisterFlags(fs) + c.Cfg.RegisterFlags(fs) } // appendGenesisTxs saves the given transactions to the genesis doc @@ -74,3 +75,35 @@ func appendGenesisTxs(genesis *types.GenesisDoc, txs []std.Tx) error { return nil } + +// txStore is a wrapper for TM2 transactions +type txStore []std.Tx + +// leftMerge merges the two tx stores, with +// preference to the left +func (i *txStore) leftMerge(b txStore) error { + // Build out the tx hash map + txHashMap := make(map[string]struct{}, len(*i)) + + for _, tx := range *i { + txHash, err := getTxHash(tx) + if err != nil { + return err + } + + txHashMap[txHash] = struct{}{} + } + + for _, tx := range b { + txHash, err := getTxHash(tx) + if err != nil { + return err + } + + if _, exists := txHashMap[txHash]; !exists { + *i = append(*i, tx) + } + } + + return nil +} diff --git a/gno.land/cmd/gnoland/genesis_txs_add.go b/contribs/gnogenesis/internal/txs/txs_add.go similarity index 97% rename from gno.land/cmd/gnoland/genesis_txs_add.go rename to contribs/gnogenesis/internal/txs/txs_add.go index 7e7fd25b21e..22b3b1b966a 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add.go +++ b/contribs/gnogenesis/internal/txs/txs_add.go @@ -1,4 +1,4 @@ -package main +package txs import ( "github.com/gnolang/gno/tm2/pkg/commands" diff --git a/gno.land/cmd/gnoland/genesis_txs_add_packages.go b/contribs/gnogenesis/internal/txs/txs_add_packages.go similarity index 92% rename from gno.land/cmd/gnoland/genesis_txs_add_packages.go rename to contribs/gnogenesis/internal/txs/txs_add_packages.go index 56d165c070b..b07adc777a7 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add_packages.go +++ b/contribs/gnogenesis/internal/txs/txs_add_packages.go @@ -1,4 +1,4 @@ -package main +package txs import ( "context" @@ -16,6 +16,7 @@ import ( var errInvalidPackageDir = errors.New("invalid package directory") var ( + // Keep in sync with gno.land/cmd/start.go genesisDeployAddress = crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // test1 genesisDeployFee = std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000))) ) @@ -42,7 +43,7 @@ func execTxsAddPackages( args []string, ) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -69,7 +70,7 @@ func execTxsAddPackages( } // Save the updated genesis - if err := genesis.SaveAs(cfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_txs_add_packages_test.go b/contribs/gnogenesis/internal/txs/txs_add_packages_test.go similarity index 88% rename from gno.land/cmd/gnoland/genesis_txs_add_packages_test.go rename to contribs/gnogenesis/internal/txs/txs_add_packages_test.go index 20c4f84c9ed..c814ccde957 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add_packages_test.go +++ b/contribs/gnogenesis/internal/txs/txs_add_packages_test.go @@ -1,4 +1,4 @@ -package main +package txs import ( "context" @@ -7,6 +7,7 @@ import ( "path/filepath" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" vmm "github.com/gnolang/gno/gno.land/pkg/sdk/vm" "github.com/gnolang/gno/tm2/pkg/bft/types" @@ -23,10 +24,8 @@ func TestGenesis_Txs_Add_Packages(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "packages", "--genesis-path", @@ -35,7 +34,7 @@ func TestGenesis_Txs_Add_Packages(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid package dir", func(t *testing.T) { @@ -44,14 +43,12 @@ func TestGenesis_Txs_Add_Packages(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "packages", "--genesis-path", @@ -69,7 +66,7 @@ func TestGenesis_Txs_Add_Packages(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Prepare the package @@ -99,10 +96,8 @@ func TestGenesis_Txs_Add_Packages(t *testing.T) { ) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "packages", "--genesis-path", diff --git a/gno.land/cmd/gnoland/genesis_txs_add_sheet.go b/contribs/gnogenesis/internal/txs/txs_add_sheet.go similarity index 93% rename from gno.land/cmd/gnoland/genesis_txs_add_sheet.go rename to contribs/gnogenesis/internal/txs/txs_add_sheet.go index 261a050029c..88673bc29bd 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add_sheet.go +++ b/contribs/gnogenesis/internal/txs/txs_add_sheet.go @@ -1,4 +1,4 @@ -package main +package txs import ( "context" @@ -39,7 +39,7 @@ func execTxsAddSheet( args []string, ) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -74,7 +74,7 @@ func execTxsAddSheet( } // Save the updated genesis - if err := genesis.SaveAs(cfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go b/contribs/gnogenesis/internal/txs/txs_add_sheet_test.go similarity index 89% rename from gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go rename to contribs/gnogenesis/internal/txs/txs_add_sheet_test.go index a70446cfe6c..a174905c237 100644 --- a/gno.land/cmd/gnoland/genesis_txs_add_sheet_test.go +++ b/contribs/gnogenesis/internal/txs/txs_add_sheet_test.go @@ -1,4 +1,4 @@ -package main +package txs import ( "context" @@ -6,6 +6,7 @@ import ( "strings" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" "github.com/gnolang/gno/tm2/pkg/amino" @@ -70,10 +71,8 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "sheets", "--genesis-path", @@ -82,7 +81,7 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid txs file", func(t *testing.T) { @@ -91,14 +90,12 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "sheets", "--genesis-path", @@ -117,14 +114,12 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "sheets", "--genesis-path", @@ -142,14 +137,12 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "sheets", "--genesis-path", @@ -171,7 +164,7 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Prepare the transactions file @@ -187,10 +180,8 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { require.NoError(t, err) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "sheets", "--genesis-path", @@ -226,7 +217,7 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesisState := gnoland.GnoGenesisState{ Txs: txs[0 : len(txs)/2], } @@ -247,10 +238,8 @@ func TestGenesis_Txs_Add_Sheets(t *testing.T) { require.NoError(t, err) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "add", "sheets", "--genesis-path", diff --git a/gno.land/cmd/gnoland/genesis_txs_export.go b/contribs/gnogenesis/internal/txs/txs_export.go similarity index 92% rename from gno.land/cmd/gnoland/genesis_txs_export.go rename to contribs/gnogenesis/internal/txs/txs_export.go index bf54236b31f..0409f1fd0ac 100644 --- a/gno.land/cmd/gnoland/genesis_txs_export.go +++ b/contribs/gnogenesis/internal/txs/txs_export.go @@ -1,19 +1,17 @@ -package main +package txs import ( "context" - "errors" "fmt" "os" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" ) -var errNoOutputFile = errors.New("no output file path specified") - // newTxsExportCmd creates the genesis txs export subcommand func newTxsExportCmd(txsCfg *txsCfg, io commands.IO) *commands.Command { return commands.NewCommand( @@ -32,7 +30,7 @@ func newTxsExportCmd(txsCfg *txsCfg, io commands.IO) *commands.Command { func execTxsExport(cfg *txsCfg, io commands.IO, args []string) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -51,7 +49,7 @@ func execTxsExport(cfg *txsCfg, io commands.IO, args []string) error { // Make sure the output file path is specified if len(args) == 0 { - return errNoOutputFile + return common.ErrNoOutputFile } // Open output file diff --git a/gno.land/cmd/gnoland/genesis_txs_export_test.go b/contribs/gnogenesis/internal/txs/txs_export_test.go similarity index 84% rename from gno.land/cmd/gnoland/genesis_txs_export_test.go rename to contribs/gnogenesis/internal/txs/txs_export_test.go index 9927f671efb..47fc594d2ec 100644 --- a/gno.land/cmd/gnoland/genesis_txs_export_test.go +++ b/contribs/gnogenesis/internal/txs/txs_export_test.go @@ -1,10 +1,11 @@ -package main +package txs import ( "bufio" "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/commands" @@ -21,10 +22,8 @@ func TestGenesis_Txs_Export(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "export", "--genesis-path", "dummy-path", @@ -32,7 +31,7 @@ func TestGenesis_Txs_Export(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid genesis app state", func(t *testing.T) { @@ -41,15 +40,13 @@ func TestGenesis_Txs_Export(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = nil // no app state require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "export", "--genesis-path", tempGenesis.Name(), @@ -66,17 +63,15 @@ func TestGenesis_Txs_Export(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Txs: generateDummyTxs(t, 1), } require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "export", "--genesis-path", tempGenesis.Name(), @@ -84,7 +79,7 @@ func TestGenesis_Txs_Export(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errNoOutputFile.Error()) + assert.ErrorContains(t, cmdErr, common.ErrNoOutputFile.Error()) }) t.Run("valid txs export", func(t *testing.T) { @@ -96,7 +91,7 @@ func TestGenesis_Txs_Export(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Txs: txs, } @@ -107,10 +102,8 @@ func TestGenesis_Txs_Export(t *testing.T) { t.Cleanup(outputCleanup) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "export", "--genesis-path", tempGenesis.Name(), diff --git a/gno.land/cmd/gnoland/genesis_txs_list.go b/contribs/gnogenesis/internal/txs/txs_list.go similarity index 86% rename from gno.land/cmd/gnoland/genesis_txs_list.go rename to contribs/gnogenesis/internal/txs/txs_list.go index c68fbc30803..c7867da5027 100644 --- a/gno.land/cmd/gnoland/genesis_txs_list.go +++ b/contribs/gnogenesis/internal/txs/txs_list.go @@ -1,4 +1,4 @@ -package main +package txs import ( "bytes" @@ -6,6 +6,7 @@ import ( "errors" "fmt" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" @@ -33,9 +34,9 @@ func newTxsListCmd(txsCfg *txsCfg, io commands.IO) *commands.Command { } func execTxsListCmd(io commands.IO, cfg *txsCfg) error { - genesis, err := types.GenesisDocFromFile(cfg.genesisPath) + genesis, err := types.GenesisDocFromFile(cfg.GenesisPath) if err != nil { - return fmt.Errorf("%w, %w", errUnableToLoadGenesis, err) + return fmt.Errorf("%w, %w", common.ErrUnableToLoadGenesis, err) } gs, ok := genesis.AppState.(gnoland.GnoGenesisState) diff --git a/gno.land/cmd/gnoland/genesis_txs_list_test.go b/contribs/gnogenesis/internal/txs/txs_list_test.go similarity index 83% rename from gno.land/cmd/gnoland/genesis_txs_list_test.go rename to contribs/gnogenesis/internal/txs/txs_list_test.go index d18c2f4d641..5129533dc8f 100644 --- a/gno.land/cmd/gnoland/genesis_txs_list_test.go +++ b/contribs/gnogenesis/internal/txs/txs_list_test.go @@ -1,10 +1,11 @@ -package main +package txs import ( "bytes" "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -20,10 +21,8 @@ func TestGenesis_List_All(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "list", "--genesis-path", "", @@ -31,7 +30,7 @@ func TestGenesis_List_All(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorIs(t, cmdErr, errUnableToLoadGenesis) + assert.ErrorIs(t, cmdErr, common.ErrUnableToLoadGenesis) }) t.Run("list all txs", func(t *testing.T) { @@ -43,7 +42,7 @@ func TestGenesis_List_All(t *testing.T) { // Generate dummy txs txs := generateDummyTxs(t, 10) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Txs: txs, } @@ -53,10 +52,8 @@ func TestGenesis_List_All(t *testing.T) { buf := bytes.NewBuffer(nil) cio.SetOut(commands.WriteNopCloser(buf)) - cmd := newRootCmd(cio) + cmd := NewTxsCmd(cio) args := []string{ - "genesis", - "txs", "list", "--genesis-path", tempGenesis.Name(), diff --git a/gno.land/cmd/gnoland/genesis_txs_remove.go b/contribs/gnogenesis/internal/txs/txs_remove.go similarity index 94% rename from gno.land/cmd/gnoland/genesis_txs_remove.go rename to contribs/gnogenesis/internal/txs/txs_remove.go index 49c650f4670..f767e19bc90 100644 --- a/gno.land/cmd/gnoland/genesis_txs_remove.go +++ b/contribs/gnogenesis/internal/txs/txs_remove.go @@ -1,4 +1,4 @@ -package main +package txs import ( "context" @@ -37,7 +37,7 @@ func newTxsRemoveCmd(txsCfg *txsCfg, io commands.IO) *commands.Command { func execTxsRemove(cfg *txsCfg, io commands.IO, args []string) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -87,7 +87,7 @@ func execTxsRemove(cfg *txsCfg, io commands.IO, args []string) error { genesis.AppState = state // Save the updated genesis - if err := genesis.SaveAs(cfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_txs_remove_test.go b/contribs/gnogenesis/internal/txs/txs_remove_test.go similarity index 86% rename from gno.land/cmd/gnoland/genesis_txs_remove_test.go rename to contribs/gnogenesis/internal/txs/txs_remove_test.go index ff5af479449..c031e0d342e 100644 --- a/gno.land/cmd/gnoland/genesis_txs_remove_test.go +++ b/contribs/gnogenesis/internal/txs/txs_remove_test.go @@ -1,9 +1,10 @@ -package main +package txs import ( "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -19,10 +20,8 @@ func TestGenesis_Txs_Remove(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "remove", "--genesis-path", "dummy-path", @@ -30,7 +29,7 @@ func TestGenesis_Txs_Remove(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid genesis app state", func(t *testing.T) { @@ -39,15 +38,13 @@ func TestGenesis_Txs_Remove(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = nil // no app state require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "remove", "--genesis-path", tempGenesis.Name(), @@ -66,17 +63,15 @@ func TestGenesis_Txs_Remove(t *testing.T) { // Generate dummy txs txs := generateDummyTxs(t, 10) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Txs: txs, } require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "remove", "--genesis-path", tempGenesis.Name(), @@ -96,7 +91,7 @@ func TestGenesis_Txs_Remove(t *testing.T) { // Generate dummy txs txs := generateDummyTxs(t, 10) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() genesis.AppState = gnoland.GnoGenesisState{ Txs: txs, } @@ -106,10 +101,8 @@ func TestGenesis_Txs_Remove(t *testing.T) { require.NoError(t, err) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewTxsCmd(commands.NewTestIO()) args := []string{ - "genesis", - "txs", "remove", "--genesis-path", tempGenesis.Name(), diff --git a/gno.land/cmd/gnoland/genesis_validator.go b/contribs/gnogenesis/internal/validator/validator.go similarity index 68% rename from gno.land/cmd/gnoland/genesis_validator.go rename to contribs/gnogenesis/internal/validator/validator.go index 91d3e4af7dd..8cd84f5c9bf 100644 --- a/gno.land/cmd/gnoland/genesis_validator.go +++ b/contribs/gnogenesis/internal/validator/validator.go @@ -1,27 +1,28 @@ -package main +package validator import ( "flag" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/tm2/pkg/commands" ) type validatorCfg struct { - commonCfg + common.Cfg address string } -// newValidatorCmd creates the genesis validator subcommand -func newValidatorCmd(io commands.IO) *commands.Command { +// NewValidatorCmd creates the genesis validator subcommand +func NewValidatorCmd(io commands.IO) *commands.Command { cfg := &validatorCfg{ - commonCfg: commonCfg{}, + Cfg: common.Cfg{}, } cmd := commands.NewCommand( commands.Metadata{ Name: "validator", - ShortUsage: "validator [flags]", + ShortUsage: " [flags]", ShortHelp: "validator set management in genesis.json", LongHelp: "Manipulates the genesis.json validator set", }, @@ -38,7 +39,7 @@ func newValidatorCmd(io commands.IO) *commands.Command { } func (c *validatorCfg) RegisterFlags(fs *flag.FlagSet) { - c.commonCfg.RegisterFlags(fs) + c.Cfg.RegisterFlags(fs) fs.StringVar( &c.address, diff --git a/gno.land/cmd/gnoland/genesis_validator_add.go b/contribs/gnogenesis/internal/validator/validator_add.go similarity index 95% rename from gno.land/cmd/gnoland/genesis_validator_add.go rename to contribs/gnogenesis/internal/validator/validator_add.go index 6c44ad93f89..45744f98e82 100644 --- a/gno.land/cmd/gnoland/genesis_validator_add.go +++ b/contribs/gnogenesis/internal/validator/validator_add.go @@ -1,4 +1,4 @@ -package main +package validator import ( "context" @@ -71,7 +71,7 @@ func (c *validatorAddCfg) RegisterFlags(fs *flag.FlagSet) { func execValidatorAdd(cfg *validatorAddCfg, io commands.IO) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -124,7 +124,7 @@ func execValidatorAdd(cfg *validatorAddCfg, io commands.IO) error { genesis.Validators = append(genesis.Validators, validator) // Save the updated genesis - if err := genesis.SaveAs(cfg.rootCfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.rootCfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_validator_add_test.go b/contribs/gnogenesis/internal/validator/validator_add_test.go similarity index 66% rename from gno.land/cmd/gnoland/genesis_validator_add_test.go rename to contribs/gnogenesis/internal/validator/validator_add_test.go index 528255b3029..4e6155137a3 100644 --- a/gno.land/cmd/gnoland/genesis_validator_add_test.go +++ b/contribs/gnogenesis/internal/validator/validator_add_test.go @@ -1,61 +1,18 @@ -package main +package validator import ( "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/crypto" - "github.com/gnolang/gno/tm2/pkg/crypto/bip39" - "github.com/gnolang/gno/tm2/pkg/crypto/hd" - "github.com/gnolang/gno/tm2/pkg/crypto/keys/client" - "github.com/gnolang/gno/tm2/pkg/crypto/secp256k1" "github.com/gnolang/gno/tm2/pkg/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -// getDummyKey generates a random public key, -// and returns the key info -func getDummyKey(t *testing.T) crypto.PubKey { - t.Helper() - - mnemonic, err := client.GenerateMnemonic(256) - require.NoError(t, err) - - seed := bip39.NewSeed(mnemonic, "") - - return generateKeyFromSeed(seed, 0).PubKey() -} - -// generateKeyFromSeed generates a private key from -// the provided seed and index -func generateKeyFromSeed(seed []byte, index uint32) crypto.PrivKey { - pathParams := hd.NewFundraiserParams(0, crypto.CoinType, index) - - masterPriv, ch := hd.ComputeMastersFromSeed(seed) - - //nolint:errcheck // This derivation can never error out, since the path params - // are always going to be valid - derivedPriv, _ := hd.DerivePrivateKeyForPath(masterPriv, ch, pathParams.String()) - - return secp256k1.PrivKeySecp256k1(derivedPriv) -} - -// getDummyKeys generates random keys for testing -func getDummyKeys(t *testing.T, count int) []crypto.PubKey { - t.Helper() - - dummyKeys := make([]crypto.PubKey, count) - - for i := 0; i < count; i++ { - dummyKeys[i] = getDummyKey(t) - } - - return dummyKeys -} - func TestGenesis_Validator_Add(t *testing.T) { t.Parallel() @@ -63,10 +20,8 @@ func TestGenesis_Validator_Add(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", "dummy-path", @@ -74,7 +29,7 @@ func TestGenesis_Validator_Add(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid validator address", func(t *testing.T) { @@ -83,14 +38,12 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), @@ -109,16 +62,14 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) - key := getDummyKey(t) + key := common.GetDummyKey(t) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), @@ -139,16 +90,14 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) - key := getDummyKey(t) + key := common.GetDummyKey(t) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), @@ -169,16 +118,14 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) - key := getDummyKey(t) + key := common.GetDummyKey(t) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), @@ -201,16 +148,14 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) - dummyKeys := getDummyKeys(t, 2) + dummyKeys := common.GetDummyKeys(t, 2) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), @@ -233,8 +178,8 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - dummyKeys := getDummyKeys(t, 2) - genesis := getDefaultGenesis() + dummyKeys := common.GetDummyKeys(t, 2) + genesis := common.GetDefaultGenesis() // Set an existing validator genesis.Validators = append(genesis.Validators, types.GenesisValidator{ @@ -247,10 +192,8 @@ func TestGenesis_Validator_Add(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), @@ -273,16 +216,14 @@ func TestGenesis_Validator_Add(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - key := getDummyKey(t) - genesis := getDefaultGenesis() + key := common.GetDummyKey(t) + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "add", "--genesis-path", tempGenesis.Name(), diff --git a/gno.land/cmd/gnoland/genesis_validator_remove.go b/contribs/gnogenesis/internal/validator/validator_remove.go similarity index 92% rename from gno.land/cmd/gnoland/genesis_validator_remove.go rename to contribs/gnogenesis/internal/validator/validator_remove.go index 48a15a9abaf..0206fe7d58d 100644 --- a/gno.land/cmd/gnoland/genesis_validator_remove.go +++ b/contribs/gnogenesis/internal/validator/validator_remove.go @@ -1,4 +1,4 @@ -package main +package validator import ( "context" @@ -29,7 +29,7 @@ func newValidatorRemoveCmd(rootCfg *validatorCfg, io commands.IO) *commands.Comm func execValidatorRemove(cfg *validatorCfg, io commands.IO) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -58,7 +58,7 @@ func execValidatorRemove(cfg *validatorCfg, io commands.IO) error { genesis.Validators = append(genesis.Validators[:index], genesis.Validators[index+1:]...) // Save the updated genesis - if err := genesis.SaveAs(cfg.genesisPath); err != nil { + if err := genesis.SaveAs(cfg.GenesisPath); err != nil { return fmt.Errorf("unable to save genesis.json, %w", err) } diff --git a/gno.land/cmd/gnoland/genesis_validator_remove_test.go b/contribs/gnogenesis/internal/validator/validator_remove_test.go similarity index 81% rename from gno.land/cmd/gnoland/genesis_validator_remove_test.go rename to contribs/gnogenesis/internal/validator/validator_remove_test.go index e73e867c5c3..78821f4abee 100644 --- a/gno.land/cmd/gnoland/genesis_validator_remove_test.go +++ b/contribs/gnogenesis/internal/validator/validator_remove_test.go @@ -1,9 +1,10 @@ -package main +package validator import ( "context" "testing" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/testutils" @@ -18,10 +19,8 @@ func TestGenesis_Validator_Remove(t *testing.T) { t.Parallel() // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "remove", "--genesis-path", "dummy-path", @@ -29,7 +28,7 @@ func TestGenesis_Validator_Remove(t *testing.T) { // Run the command cmdErr := cmd.ParseAndRun(context.Background(), args) - assert.ErrorContains(t, cmdErr, errUnableToLoadGenesis.Error()) + assert.ErrorContains(t, cmdErr, common.ErrUnableToLoadGenesis.Error()) }) t.Run("invalid validator address", func(t *testing.T) { @@ -38,14 +37,12 @@ func TestGenesis_Validator_Remove(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "remove", "--genesis-path", tempGenesis.Name(), @@ -64,8 +61,8 @@ func TestGenesis_Validator_Remove(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - dummyKeys := getDummyKeys(t, 2) - genesis := getDefaultGenesis() + dummyKeys := common.GetDummyKeys(t, 2) + genesis := common.GetDefaultGenesis() // Set an existing validator genesis.Validators = append(genesis.Validators, types.GenesisValidator{ @@ -78,10 +75,8 @@ func TestGenesis_Validator_Remove(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "remove", "--genesis-path", tempGenesis.Name(), @@ -100,9 +95,9 @@ func TestGenesis_Validator_Remove(t *testing.T) { tempGenesis, cleanup := testutils.NewTestFile(t) t.Cleanup(cleanup) - dummyKey := getDummyKey(t) + dummyKey := common.GetDummyKey(t) - genesis := getDefaultGenesis() + genesis := common.GetDefaultGenesis() // Set an existing validator genesis.Validators = append(genesis.Validators, types.GenesisValidator{ @@ -115,10 +110,8 @@ func TestGenesis_Validator_Remove(t *testing.T) { require.NoError(t, genesis.SaveAs(tempGenesis.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewValidatorCmd(commands.NewTestIO()) args := []string{ - "genesis", - "validator", "remove", "--genesis-path", tempGenesis.Name(), diff --git a/gno.land/cmd/gnoland/genesis_verify.go b/contribs/gnogenesis/internal/verify/verify.go similarity index 80% rename from gno.land/cmd/gnoland/genesis_verify.go rename to contribs/gnogenesis/internal/verify/verify.go index 112b075a58c..97ad14cb7f6 100644 --- a/gno.land/cmd/gnoland/genesis_verify.go +++ b/contribs/gnogenesis/internal/verify/verify.go @@ -1,4 +1,4 @@ -package main +package verify import ( "context" @@ -6,6 +6,7 @@ import ( "flag" "fmt" + "github.com/gnolang/contribs/gnogenesis/internal/common" "github.com/gnolang/gno/gno.land/pkg/gnoland" "github.com/gnolang/gno/tm2/pkg/bft/types" "github.com/gnolang/gno/tm2/pkg/commands" @@ -14,17 +15,17 @@ import ( var errInvalidGenesisState = errors.New("invalid genesis state type") type verifyCfg struct { - commonCfg + common.Cfg } -// newVerifyCmd creates the genesis verify subcommand -func newVerifyCmd(io commands.IO) *commands.Command { +// NewVerifyCmd creates the genesis verify subcommand +func NewVerifyCmd(io commands.IO) *commands.Command { cfg := &verifyCfg{} return commands.NewCommand( commands.Metadata{ Name: "verify", - ShortUsage: "verify [flags]", + ShortUsage: "[flags]", ShortHelp: "verifies a genesis.json", LongHelp: "Verifies a node's genesis.json", }, @@ -36,12 +37,12 @@ func newVerifyCmd(io commands.IO) *commands.Command { } func (c *verifyCfg) RegisterFlags(fs *flag.FlagSet) { - c.commonCfg.RegisterFlags(fs) + c.Cfg.RegisterFlags(fs) } func execVerify(cfg *verifyCfg, io commands.IO) error { // Load the genesis - genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath) + genesis, loadErr := types.GenesisDocFromFile(cfg.GenesisPath) if loadErr != nil { return fmt.Errorf("unable to load genesis, %w", loadErr) } @@ -73,7 +74,7 @@ func execVerify(cfg *verifyCfg, io commands.IO) error { } } - io.Printfln("Genesis at %s is valid", cfg.genesisPath) + io.Printfln("Genesis at %s is valid", cfg.GenesisPath) return nil } diff --git a/gno.land/cmd/gnoland/genesis_verify_test.go b/contribs/gnogenesis/internal/verify/verify_test.go similarity index 90% rename from gno.land/cmd/gnoland/genesis_verify_test.go rename to contribs/gnogenesis/internal/verify/verify_test.go index 9c93519e495..76009c34c94 100644 --- a/gno.land/cmd/gnoland/genesis_verify_test.go +++ b/contribs/gnogenesis/internal/verify/verify_test.go @@ -1,4 +1,4 @@ -package main +package verify import ( "context" @@ -53,10 +53,8 @@ func TestGenesis_Verify(t *testing.T) { require.NoError(t, g.SaveAs(tempFile.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewVerifyCmd(commands.NewTestIO()) args := []string{ - "genesis", - "verify", "--genesis-path", tempFile.Name(), } @@ -84,10 +82,8 @@ func TestGenesis_Verify(t *testing.T) { require.NoError(t, g.SaveAs(tempFile.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewVerifyCmd(commands.NewTestIO()) args := []string{ - "genesis", - "verify", "--genesis-path", tempFile.Name(), } @@ -112,10 +108,8 @@ func TestGenesis_Verify(t *testing.T) { require.NoError(t, g.SaveAs(tempFile.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewVerifyCmd(commands.NewTestIO()) args := []string{ - "genesis", - "verify", "--genesis-path", tempFile.Name(), } @@ -135,10 +129,8 @@ func TestGenesis_Verify(t *testing.T) { require.NoError(t, g.SaveAs(tempFile.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewVerifyCmd(commands.NewTestIO()) args := []string{ - "genesis", - "verify", "--genesis-path", tempFile.Name(), } @@ -159,10 +151,8 @@ func TestGenesis_Verify(t *testing.T) { require.NoError(t, g.SaveAs(tempFile.Name())) // Create the command - cmd := newRootCmd(commands.NewTestIO()) + cmd := NewVerifyCmd(commands.NewTestIO()) args := []string{ - "genesis", - "verify", "--genesis-path", tempFile.Name(), } diff --git a/contribs/gnogenesis/main.go b/contribs/gnogenesis/main.go new file mode 100644 index 00000000000..a5beb2518dd --- /dev/null +++ b/contribs/gnogenesis/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "context" + "os" + + "github.com/gnolang/gno/tm2/pkg/commands" +) + +func main() { + cmd := newGenesisCmd(commands.NewDefaultIO()) + + cmd.Execute(context.Background(), os.Args[1:]) +} diff --git a/docs/gno-infrastructure/validators/faq.md b/docs/gno-infrastructure/validators/faq.md index c345b49724a..1a065a5ca56 100644 --- a/docs/gno-infrastructure/validators/faq.md +++ b/docs/gno-infrastructure/validators/faq.md @@ -104,41 +104,6 @@ either a full node or a pruned node, it is important to retain enough blocks to ## Technical References -### How do I generate `genesis.json`? - -`genesis.json` is the file that is used to create the initial state of the chain. To generate `genesis.json`, use -the `gnoland genesis generate` command. Refer -to [this section](../../gno-tooling/cli/gnoland.md#gnoland-genesis-generate-flags) for various flags that allow you to -manipulate the file. - -:::warning - -Editing generated genesis.json manually is extremely dangerous. It may corrupt chain initial state which leads chain to -not start - -::: - -### How do I add or remove validators from `genesis.json`? - -Validators inside `genesis.json` will be included in the validator set at genesis. To manipulate the genesis validator -set, use the `gnoland genesis validator` command with the `add` or `remove` subcommands. Refer -to [this section](../../gno-tooling/cli/gnoland.md#gnoland-genesis-validator-flags) for flags that allow you to -configure the name or the voting power of the validator. - -### How do I add the balance information to the `genesis.json`? - -You may premine coins to various addresses. To modify the balances of addresses at genesis, use -the `gnoland genesis balances` command with the `add` or `remove` subcommands. Refer -to [this section](../../gno-tooling/cli/gnoland.md#gnoland-genesis-balances-add-flags) for various flags that allow you -to update the entire balance sheet with a file or modify the balance of a single address. - -:::info - -Not only `ugnot`, but other coins are accepted. However, be aware that coins other than `ugnot` may not work(send, and -etc.) properly. - -::: - ### How do I initialize `gno secrets`? The `gno secrets init` command allows you to initialize the private information required to run the validator, including 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..aab76eefbaf 100644 --- a/docs/gno-infrastructure/validators/setting-up-a-new-chain.md +++ b/docs/gno-infrastructure/validators/setting-up-a-new-chain.md @@ -19,7 +19,7 @@ Additionally, you will see the different options you can use to make your Gno in ## Installation -To install the `gnoland` binary, clone the Gno monorepo: +To install the `gnoland` and `gnogenesis` binaries, clone the Gno monorepo: ```bash git clone https://github.com/gnolang/gno.git @@ -30,7 +30,7 @@ Makefile to install the `gnoland` binary: ```bash cd gno.land -make install.gnoland +make install.gnoland install.gnogenesis ``` To verify that you've installed the binary properly and that you are able to use @@ -93,7 +93,8 @@ 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 `genesis.json`, then 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. ::: @@ -201,7 +202,7 @@ executed. Generating an empty `genesis.json` is relatively straightforward: ```shell -gnoland genesis generate +gnogenesis generate ``` The resulting `genesis.json` is empty: @@ -232,7 +233,7 @@ This will generate a `genesis.json` in the calling directory, by default. To che generating the `genesis.json`, you can run the command using the `--help` flag: ```shell -gnoland genesis generate --help +gnogenesis generate --help USAGE generate [flags] @@ -257,7 +258,7 @@ present challenges with users who expect them to be present. The `examples` directory is located in the `$GNOROOT` location, or the local gno repository clone. ```bash -gnoland genesis txs add packages ./examples +gnogenesis txs add packages ./examples ``` ### 4. Add the initial validator set @@ -288,7 +289,7 @@ Updating the `genesis.json` is relatively simple, running the following command validator set: ```shell -gnoland genesis validator add \ +gnogenesis validator add \ --address g14j4dlsh3jzgmhezzp9v8xp7wxs4mvyskuw5ljl \ --pub-key gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zqaqle3fdduqul4slg6zllypq9r8gj4wlfucy6qfnzmjcgqv675kxjz8jvk \ --name Cuttlas diff --git a/docs/gno-tooling/cli/gnoland.md b/docs/gno-tooling/cli/gnoland.md index 18175871d90..037a1f19d03 100644 --- a/docs/gno-tooling/cli/gnoland.md +++ b/docs/gno-tooling/cli/gnoland.md @@ -29,164 +29,6 @@ Starts the Gnoland blockchain node, with accompanying setup. | `log-level` | String | The log level for the gnoland node. (default: `debug`) | | `skip-failing-genesis-txs` | Boolean | Doesn’t panic when replaying invalid genesis txs. When starting a production-level chain, it is recommended to set this value to `true` to monitor and analyze failing transactions. (default: `false`) | -### gnoland genesis \ [flags] [\...] - -Gno `genesis.json` manipulation suite for managing genesis parameters. - -#### SUBCOMMANDS - -| Name | Description | -|-------------|---------------------------------------------| -| `generate` | Generates a fresh `genesis.json`. | -| `validator` | Validator set management in `genesis.json`. | -| `verify` | Verifies a `genesis.json`. | -| `balances` | Manages `genesis.json` account balances. | -| `txs` | Manages the initial genesis transactions. | - -### gnoland genesis generate [flags] - -Generates a node's `genesis.json` based on specified parameters. - -#### FLAGS - -| Name | Type | Description | -|------------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `block-max-data-bytes` | Int | The max size of the block data.(default: `2000000`) | -| `block-max-gas` | Int | The max gas limit for the block. (default: `100000000`) | -| `block-max-tx-bytes` | Int | The max size of the block transaction. (default: `1000000`) | -| `block-time-itoa` | Int | The block time itoa (in ms). (default: `100`) | -| `chain-id` | String | The ID of the chain. (default: `dev`) | -| `genesis-time` | Int | The genesis creation time. (default: `utc now timestamp`) | -| `output-path` : | String | The output path for the `genesis.json`. If the genesis-time of the Genesis File is set to a future time, the chain will automatically start at that time if the node is online. (default: `./genesis.json`) | - -### gnoland genesis validator \ [flags] - -Manipulates the `genesis.json` validator set. - -#### SUBCOMANDS - -| Name | Description | -|----------|----------------------------------------------| -| `add` | Adds a new validator to the `genesis.json`. | -| `remove` | Removes a validator from the `genesis.json`. | - -#### FLAGS - -| Name | Type | Description | -|----------------|--------|------------------------------------------------------------| -| `address` | String | The gno bech32 address of the validator. | -| `genesis-path` | String | The path to the `genesis.json`. (default `./genesis.json`) | - -### gnoland genesis validator add [flags] - -Adds a new validator to the `genesis.json`. - -#### FLAGS - -| Name | Type | Description | -|----------------|--------|-----------------------------------------------------------------| -| `address` | String | The gno bech32 address of the validator. | -| `genesis-path` | String | The path to the `genesis.json`. (default: `./genesis.json`) | -| `name` | String | The name of the validator (must be unique). | -| `power` | Uint | The voting power of the validator (must be > 0). (default: `1`) | -| `pub-key` | String | The bech32 string representation of the validator's public key. | - -```bash -gnoland genesis validator add \ --address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h \ --name test1 \ --pub-key gpub1pggj7ard9eg82cjtv4u52epjx56nzwgjyg9zplmcmggxyxyrch0zcyg684yxmerullv3l6hmau58sk4eyxskmny9h7lsnz - -Validator with address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h added to genesis file -``` - -### gnoland genesis validator remove [flags] - -Removes a validator from the `genesis.json`. - -#### FLAGS - -| Name | Type | Description | -|----------------|--------|-------------------------------------------------------------| -| `address` | String | The gno bech32 address of the validator. | -| `genesis-path` | String | The path to the `genesis.json`. (default: `./genesis.json)` | - -```bash -gnoland genesis validator remove \ --address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h - -Validator with address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h removed from genesis file -``` - -### gnoland genesis verify \ [flags] [\…] - -Verifies a `genesis.json`. - -#### FLAGS - -| Name | Type | Description | -|----------------|--------|-----------------------------------------------------------| -| `genesis-path` | String | The path to the `genesis.json`. (default: `genesis.json`) | - -### gnoland genesis balances \ [flags] [\…] - -Manages `genesis.json` account balances. - -#### SUBCOMMANDS - -| Name | Description | -|----------|--------------------------------------------------------| -| `add` | Adds the balance information. | -| `remove` | Removes the balance information of a specific account. | - -### gnoland genesis balances add [flags] - -#### FLAGS - -| Name | Type | Description | -|-----------------|--------|--------------------------------------------------------------------------------------------| -| `balance-sheet` | String | The path to the balance file containing addresses in the format `
    =ugnot`. | -| `genesis-path` | String | The path to the `genesis.json` (default: `./genesis.json`) | -| `parse-export` | String | The path to the transaction export containing a list of transactions (JSONL). | -| `single` | String | The direct balance addition in the format `
    =ugnot`. | - -```bash -gnoland genesis balances add \ --single g1rzuwh5frve732k4futyw45y78rzuty4626zy6h=100ugnot - -1 pre-mines saved - -g1rzuwh5frve732k4futyw45y78rzuty4626zy6h:{[24 184 235 209 35 102 125 21 90 169 226 200 234 208 158 56 197 197 146 186] [{%!d(string=ugnot) 100}]}ugnot -``` - -### gnoland balances remove [flags] - -#### FLAGS - -| Name | Type | Description | -|----------------|--------|---------------------------------------------------------------------------------------------| -| `address` | String | The address of the account whose balance information should be removed from `genesis.json`. | -| `genesis-path` | String | The path to the `genesis.json`. (default: `./genesis.json`) | - -```bash -gnoland genesis balances remove \ --address=g1rzuwh5frve732k4futyw45y78rzuty4626zy6h - -Pre-mine information for address g1rzuwh5frve732k4futyw45y78rzuty4626zy6h removed -``` - -### gnoland txs \ [flags] [\…] - -Manages genesis transactions through input files. - -#### SUBCOMMANDS - -| Name | Description | -|----------|---------------------------------------------------| -| `add` | Imports transactions into the `genesis.json`. | -| `remove` | Removes the transactions from the `genesis.json`. | -| `export` | Exports the transactions from the `genesis.json`. | - ### gnoland secrets \ [flags] [\…] The gno secrets manipulation suite for managing the validator key, p2p key and diff --git a/gno.land/cmd/gnoland/genesis.go b/gno.land/cmd/gnoland/genesis.go deleted file mode 100644 index 37c0f8f2926..00000000000 --- a/gno.land/cmd/gnoland/genesis.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "flag" - - "github.com/gnolang/gno/tm2/pkg/commands" -) - -func newGenesisCmd(io commands.IO) *commands.Command { - cmd := commands.NewCommand( - commands.Metadata{ - Name: "genesis", - ShortUsage: "genesis [flags] [...]", - ShortHelp: "gno genesis manipulation suite", - LongHelp: "Gno genesis.json manipulation suite, for managing genesis parameters", - }, - commands.NewEmptyConfig(), - commands.HelpExec, - ) - - cmd.AddSubCommands( - newGenerateCmd(io), - newValidatorCmd(io), - newVerifyCmd(io), - newBalancesCmd(io), - newTxsCmd(io), - ) - - return cmd -} - -// commonCfg is the common -// configuration for genesis commands -// that require a genesis.json -type commonCfg struct { - genesisPath string -} - -func (c *commonCfg) RegisterFlags(fs *flag.FlagSet) { - fs.StringVar( - &c.genesisPath, - "genesis-path", - "./genesis.json", - "the path to the genesis.json", - ) -} diff --git a/gno.land/cmd/gnoland/root.go b/gno.land/cmd/gnoland/root.go index b40a1160b0b..c6143ab9cd3 100644 --- a/gno.land/cmd/gnoland/root.go +++ b/gno.land/cmd/gnoland/root.go @@ -25,7 +25,6 @@ func newRootCmd(io commands.IO) *commands.Command { cmd.AddSubCommands( newStartCmd(io), - newGenesisCmd(io), newSecretsCmd(io), newConfigCmd(io), ) diff --git a/gno.land/cmd/gnoland/start.go b/gno.land/cmd/gnoland/start.go index 8d1ee81295f..77d7e20b8ef 100644 --- a/gno.land/cmd/gnoland/start.go +++ b/gno.land/cmd/gnoland/start.go @@ -14,6 +14,7 @@ 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/log" "github.com/gnolang/gno/gnovm/pkg/gnoenv" abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" @@ -25,6 +26,7 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/events" osm "github.com/gnolang/gno/tm2/pkg/os" + "github.com/gnolang/gno/tm2/pkg/std" "github.com/gnolang/gno/tm2/pkg/telemetry" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -42,6 +44,12 @@ var startGraphic = strings.ReplaceAll(` /___/ `, "'", "`") +var ( + // Keep in sync with contribs/gnogenesis/internal/txs/txs_add_packages.go + genesisDeployAddress = crypto.MustAddressFromString("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // test1 + genesisDeployFee = std.NewFee(50000, std.MustParseCoin(ugnot.ValueString(1000000))) +) + type startCfg struct { gnoRootDir string // TODO: remove as part of https://github.com/gnolang/gno/issues/1952 skipFailingGenesisTxs bool // TODO: remove as part of https://github.com/gnolang/gno/issues/1952 diff --git a/gno.land/cmd/gnoland/types.go b/gno.land/cmd/gnoland/types.go deleted file mode 100644 index a48bfaf7b31..00000000000 --- a/gno.land/cmd/gnoland/types.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "github.com/gnolang/gno/tm2/pkg/std" -) - -// txStore is a wrapper for TM2 transactions -type txStore []std.Tx - -// leftMerge merges the two tx stores, with -// preference to the left -func (i *txStore) leftMerge(b txStore) error { - // Build out the tx hash map - txHashMap := make(map[string]struct{}, len(*i)) - - for _, tx := range *i { - txHash, err := getTxHash(tx) - if err != nil { - return err - } - - txHashMap[txHash] = struct{}{} - } - - for _, tx := range b { - txHash, err := getTxHash(tx) - if err != nil { - return err - } - - if _, exists := txHashMap[txHash]; !exists { - *i = append(*i, tx) - } - } - - return nil -} From 2a2be3944d52ba470b36b8cfaf164e428eb42840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20=C5=BDivkovi=C4=87?= Date: Tue, 29 Oct 2024 16:56:38 +0100 Subject: [PATCH 56/64] feat: `r/gov/dao` v2 (#2581) ## Description This PR introduces an upgrade to the `r/gov/dao` system: - it makes it configurable through custom implementations - added a `p/demo/simpledao` implementation - the implementations are changeable through a govdao proposal - adds weighted voting to a govdao example implementation
    Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
    --------- Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .../p/demo/combinederr/combinederr.gno | 40 + examples/gno.land/p/demo/combinederr/gno.mod | 1 + examples/gno.land/p/demo/dao/dao.gno | 33 + examples/gno.land/p/demo/dao/doc.gno | 5 + examples/gno.land/p/demo/dao/events.gno | 56 ++ examples/gno.land/p/demo/dao/executor.gno | 9 + examples/gno.land/p/demo/dao/gno.mod | 3 + examples/gno.land/p/demo/dao/proposals.gno | 62 ++ examples/gno.land/p/demo/dao/vote.gno | 69 ++ .../{r/gov/dao => p/demo/membstore}/gno.mod | 5 +- .../gno.land/p/demo/membstore/members.gno | 38 + .../gno.land/p/demo/membstore/membstore.gno | 209 +++++ .../p/demo/membstore/membstore_test.gno | 317 +++++++ examples/gno.land/p/demo/simpledao/dao.gno | 215 +++++ .../gno.land/p/demo/simpledao/dao_test.gno | 829 ++++++++++++++++++ examples/gno.land/p/demo/simpledao/gno.mod | 12 + .../gno.land/p/demo/simpledao/mock_test.gno | 97 ++ .../gno.land/p/demo/simpledao/propstore.gno | 163 ++++ .../p/demo/simpledao/propstore_test.gno | 256 ++++++ .../gno.land/p/demo/simpledao/votestore.gno | 55 ++ examples/gno.land/p/gov/executor/callback.gno | 39 + examples/gno.land/p/gov/executor/context.gno | 75 ++ .../p/gov/{proposal => executor}/gno.mod | 2 +- .../gno.land/p/gov/executor/proposal_test.gno | 180 ++++ examples/gno.land/p/gov/proposal/proposal.gno | 106 --- .../gno.land/p/gov/proposal/proposal_test.gno | 156 ---- examples/gno.land/p/gov/proposal/types.gno | 37 - examples/gno.land/r/gnoland/blog/admin.gno | 16 +- examples/gno.land/r/gnoland/blog/gno.mod | 4 +- examples/gno.land/r/gnoland/home/home.gno | 2 +- .../gno.land/r/gnoland/home/home_filetest.gno | 2 +- .../r/gnoland/valopers/{ => v2}/gno.mod | 7 +- .../r/gnoland/valopers/{ => v2}/init.gno | 0 .../r/gnoland/valopers/{ => v2}/valopers.gno | 21 +- .../valopers/{ => v2}/valopers_test.gno | 2 + examples/gno.land/r/gov/dao/bridge/bridge.gno | 39 + .../gno.land/r/gov/dao/bridge/bridge_test.gno | 64 ++ examples/gno.land/r/gov/dao/bridge/doc.gno | 4 + examples/gno.land/r/gov/dao/bridge/gno.mod | 11 + .../gno.land/r/gov/dao/bridge/mock_test.gno | 68 ++ examples/gno.land/r/gov/dao/bridge/types.gno | 17 + examples/gno.land/r/gov/dao/bridge/v2.gno | 42 + examples/gno.land/r/gov/dao/dao.gno | 207 ----- examples/gno.land/r/gov/dao/dao_test.gno | 192 ---- examples/gno.land/r/gov/dao/memberset.gno | 40 - .../gno.land/r/gov/dao/prop2_filetest.gno | 120 --- examples/gno.land/r/gov/dao/types.gno | 32 - examples/gno.land/r/gov/dao/v2/dao.gno | 121 +++ examples/gno.land/r/gov/dao/v2/gno.mod | 10 + examples/gno.land/r/gov/dao/v2/poc.gno | 92 ++ .../r/gov/dao/{ => v2}/prop1_filetest.gno | 71 +- .../gno.land/r/gov/dao/v2/prop2_filetest.gno | 110 +++ .../gno.land/r/gov/dao/v2/prop3_filetest.gno | 120 +++ examples/gno.land/r/gov/dao/voter.gno | 91 -- .../r/sys/validators/{ => v2}/doc.gno | 0 .../r/sys/validators/{ => v2}/gno.mod | 5 +- .../r/sys/validators/{ => v2}/gnosdk.gno | 0 .../r/sys/validators/{ => v2}/init.gno | 0 .../r/sys/validators/{ => v2}/poc.gno | 24 +- .../r/sys/validators/{ => v2}/validators.gno | 0 .../validators/{ => v2}/validators_test.gno | 0 gno.land/pkg/gnoland/validators.go | 2 +- 62 files changed, 3542 insertions(+), 1063 deletions(-) create mode 100644 examples/gno.land/p/demo/combinederr/combinederr.gno create mode 100644 examples/gno.land/p/demo/combinederr/gno.mod create mode 100644 examples/gno.land/p/demo/dao/dao.gno create mode 100644 examples/gno.land/p/demo/dao/doc.gno create mode 100644 examples/gno.land/p/demo/dao/events.gno create mode 100644 examples/gno.land/p/demo/dao/executor.gno create mode 100644 examples/gno.land/p/demo/dao/gno.mod create mode 100644 examples/gno.land/p/demo/dao/proposals.gno create mode 100644 examples/gno.land/p/demo/dao/vote.gno rename examples/gno.land/{r/gov/dao => p/demo/membstore}/gno.mod (54%) create mode 100644 examples/gno.land/p/demo/membstore/members.gno create mode 100644 examples/gno.land/p/demo/membstore/membstore.gno create mode 100644 examples/gno.land/p/demo/membstore/membstore_test.gno create mode 100644 examples/gno.land/p/demo/simpledao/dao.gno create mode 100644 examples/gno.land/p/demo/simpledao/dao_test.gno create mode 100644 examples/gno.land/p/demo/simpledao/gno.mod create mode 100644 examples/gno.land/p/demo/simpledao/mock_test.gno create mode 100644 examples/gno.land/p/demo/simpledao/propstore.gno create mode 100644 examples/gno.land/p/demo/simpledao/propstore_test.gno create mode 100644 examples/gno.land/p/demo/simpledao/votestore.gno create mode 100644 examples/gno.land/p/gov/executor/callback.gno create mode 100644 examples/gno.land/p/gov/executor/context.gno rename examples/gno.land/p/gov/{proposal => executor}/gno.mod (80%) create mode 100644 examples/gno.land/p/gov/executor/proposal_test.gno delete mode 100644 examples/gno.land/p/gov/proposal/proposal.gno delete mode 100644 examples/gno.land/p/gov/proposal/proposal_test.gno delete mode 100644 examples/gno.land/p/gov/proposal/types.gno rename examples/gno.land/r/gnoland/valopers/{ => v2}/gno.mod (56%) rename examples/gno.land/r/gnoland/valopers/{ => v2}/init.gno (100%) rename examples/gno.land/r/gnoland/valopers/{ => v2}/valopers.gno (90%) rename examples/gno.land/r/gnoland/valopers/{ => v2}/valopers_test.gno (97%) create mode 100644 examples/gno.land/r/gov/dao/bridge/bridge.gno create mode 100644 examples/gno.land/r/gov/dao/bridge/bridge_test.gno create mode 100644 examples/gno.land/r/gov/dao/bridge/doc.gno create mode 100644 examples/gno.land/r/gov/dao/bridge/gno.mod create mode 100644 examples/gno.land/r/gov/dao/bridge/mock_test.gno create mode 100644 examples/gno.land/r/gov/dao/bridge/types.gno create mode 100644 examples/gno.land/r/gov/dao/bridge/v2.gno delete mode 100644 examples/gno.land/r/gov/dao/dao.gno delete mode 100644 examples/gno.land/r/gov/dao/dao_test.gno delete mode 100644 examples/gno.land/r/gov/dao/memberset.gno delete mode 100644 examples/gno.land/r/gov/dao/prop2_filetest.gno delete mode 100644 examples/gno.land/r/gov/dao/types.gno create mode 100644 examples/gno.land/r/gov/dao/v2/dao.gno create mode 100644 examples/gno.land/r/gov/dao/v2/gno.mod create mode 100644 examples/gno.land/r/gov/dao/v2/poc.gno rename examples/gno.land/r/gov/dao/{ => v2}/prop1_filetest.gno (63%) create mode 100644 examples/gno.land/r/gov/dao/v2/prop2_filetest.gno create mode 100644 examples/gno.land/r/gov/dao/v2/prop3_filetest.gno delete mode 100644 examples/gno.land/r/gov/dao/voter.gno rename examples/gno.land/r/sys/validators/{ => v2}/doc.gno (100%) rename examples/gno.land/r/sys/validators/{ => v2}/gno.mod (71%) rename examples/gno.land/r/sys/validators/{ => v2}/gnosdk.gno (100%) rename examples/gno.land/r/sys/validators/{ => v2}/init.gno (100%) rename examples/gno.land/r/sys/validators/{ => v2}/poc.gno (63%) rename examples/gno.land/r/sys/validators/{ => v2}/validators.gno (100%) rename examples/gno.land/r/sys/validators/{ => v2}/validators_test.gno (100%) diff --git a/examples/gno.land/p/demo/combinederr/combinederr.gno b/examples/gno.land/p/demo/combinederr/combinederr.gno new file mode 100644 index 00000000000..f446c7846bd --- /dev/null +++ b/examples/gno.land/p/demo/combinederr/combinederr.gno @@ -0,0 +1,40 @@ +package combinederr + +import "strings" + +// CombinedError is a combined execution error +type CombinedError struct { + errors []error +} + +// Error returns the combined execution error +func (e *CombinedError) Error() string { + if len(e.errors) == 0 { + return "" + } + + var sb strings.Builder + + for _, err := range e.errors { + sb.WriteString(err.Error() + "; ") + } + + // Remove the last semicolon and space + result := sb.String() + + return result[:len(result)-2] +} + +// Add adds a new error to the execution error +func (e *CombinedError) Add(err error) { + if err == nil { + return + } + + e.errors = append(e.errors, err) +} + +// Size returns a +func (e *CombinedError) Size() int { + return len(e.errors) +} diff --git a/examples/gno.land/p/demo/combinederr/gno.mod b/examples/gno.land/p/demo/combinederr/gno.mod new file mode 100644 index 00000000000..4c99e0ba7ef --- /dev/null +++ b/examples/gno.land/p/demo/combinederr/gno.mod @@ -0,0 +1 @@ +module gno.land/p/demo/combinederr diff --git a/examples/gno.land/p/demo/dao/dao.gno b/examples/gno.land/p/demo/dao/dao.gno new file mode 100644 index 00000000000..f8ea433192f --- /dev/null +++ b/examples/gno.land/p/demo/dao/dao.gno @@ -0,0 +1,33 @@ +package dao + +const ( + ProposalAddedEvent = "ProposalAdded" // emitted when a new proposal has been added + ProposalAcceptedEvent = "ProposalAccepted" // emitted when a proposal has been accepted + ProposalNotAcceptedEvent = "ProposalNotAccepted" // emitted when a proposal has not been accepted + ProposalExecutedEvent = "ProposalExecuted" // emitted when a proposal has been executed + + ProposalEventIDKey = "proposal-id" + ProposalEventAuthorKey = "proposal-author" + ProposalEventExecutionKey = "exec-status" +) + +// ProposalRequest is a single govdao proposal request +// that contains the necessary information to +// log and generate a valid proposal +type ProposalRequest struct { + Description string // the description associated with the proposal + Executor Executor // the proposal executor +} + +// DAO defines the DAO abstraction +type DAO interface { + // PropStore is the DAO proposal storage + PropStore + + // Propose adds a new proposal to the executor-based GOVDAO. + // Returns the generated proposal ID + Propose(request ProposalRequest) (uint64, error) + + // ExecuteProposal executes the proposal with the given ID + ExecuteProposal(id uint64) error +} diff --git a/examples/gno.land/p/demo/dao/doc.gno b/examples/gno.land/p/demo/dao/doc.gno new file mode 100644 index 00000000000..3fb28204013 --- /dev/null +++ b/examples/gno.land/p/demo/dao/doc.gno @@ -0,0 +1,5 @@ +// Package dao houses common DAO building blocks (framework), which can be used or adopted by any +// specific DAO implementation. By design, the DAO should house the proposals it receives, but not the actual +// DAO members or proposal votes. These abstractions should be implemented by a separate entity, to keep the DAO +// agnostic of implementation details such as these (member / vote management). +package dao diff --git a/examples/gno.land/p/demo/dao/events.gno b/examples/gno.land/p/demo/dao/events.gno new file mode 100644 index 00000000000..97bc794e6f3 --- /dev/null +++ b/examples/gno.land/p/demo/dao/events.gno @@ -0,0 +1,56 @@ +package dao + +import ( + "std" + + "gno.land/p/demo/ufmt" +) + +// EmitProposalAdded emits an event signaling that +// a given proposal was added +func EmitProposalAdded(id uint64, proposer std.Address) { + std.Emit( + ProposalAddedEvent, + ProposalEventIDKey, ufmt.Sprintf("%d", id), + ProposalEventAuthorKey, proposer.String(), + ) +} + +// EmitProposalAccepted emits an event signaling that +// a given proposal was accepted +func EmitProposalAccepted(id uint64) { + std.Emit( + ProposalAcceptedEvent, + ProposalEventIDKey, ufmt.Sprintf("%d", id), + ) +} + +// EmitProposalNotAccepted emits an event signaling that +// a given proposal was not accepted +func EmitProposalNotAccepted(id uint64) { + std.Emit( + ProposalNotAcceptedEvent, + ProposalEventIDKey, ufmt.Sprintf("%d", id), + ) +} + +// EmitProposalExecuted emits an event signaling that +// a given proposal was executed, with the given status +func EmitProposalExecuted(id uint64, status ProposalStatus) { + std.Emit( + ProposalExecutedEvent, + ProposalEventIDKey, ufmt.Sprintf("%d", id), + ProposalEventExecutionKey, status.String(), + ) +} + +// EmitVoteAdded emits an event signaling that +// a vote was cast for a given proposal +func EmitVoteAdded(id uint64, voter std.Address, option VoteOption) { + std.Emit( + VoteAddedEvent, + VoteAddedIDKey, ufmt.Sprintf("%d", id), + VoteAddedAuthorKey, voter.String(), + VoteAddedOptionKey, option.String(), + ) +} diff --git a/examples/gno.land/p/demo/dao/executor.gno b/examples/gno.land/p/demo/dao/executor.gno new file mode 100644 index 00000000000..9291c2c53c5 --- /dev/null +++ b/examples/gno.land/p/demo/dao/executor.gno @@ -0,0 +1,9 @@ +package dao + +// Executor represents a minimal closure-oriented proposal design. +// It is intended to be used by a govdao governance proposal (v1, v2, etc) +type Executor interface { + // Execute executes the given proposal, and returns any error encountered + // during the execution + Execute() error +} diff --git a/examples/gno.land/p/demo/dao/gno.mod b/examples/gno.land/p/demo/dao/gno.mod new file mode 100644 index 00000000000..ecbab2f7692 --- /dev/null +++ b/examples/gno.land/p/demo/dao/gno.mod @@ -0,0 +1,3 @@ +module gno.land/p/demo/dao + +require gno.land/p/demo/ufmt v0.0.0-latest diff --git a/examples/gno.land/p/demo/dao/proposals.gno b/examples/gno.land/p/demo/dao/proposals.gno new file mode 100644 index 00000000000..5cad679d006 --- /dev/null +++ b/examples/gno.land/p/demo/dao/proposals.gno @@ -0,0 +1,62 @@ +package dao + +import "std" + +// ProposalStatus is the currently active proposal status, +// changed based on DAO functionality. +// Status transitions: +// +// ACTIVE -> ACCEPTED -> EXECUTION(SUCCEEDED/FAILED) +// +// ACTIVE -> NOT ACCEPTED +type ProposalStatus string + +var ( + Active ProposalStatus = "active" // proposal is still active + Accepted ProposalStatus = "accepted" // proposal gathered quorum + NotAccepted ProposalStatus = "not accepted" // proposal failed to gather quorum + ExecutionSuccessful ProposalStatus = "execution successful" // proposal is executed successfully + ExecutionFailed ProposalStatus = "execution failed" // proposal is failed during execution +) + +func (s ProposalStatus) String() string { + return string(s) +} + +// PropStore defines the proposal storage abstraction +type PropStore interface { + // Proposals returns the given paginated proposals + Proposals(offset, count uint64) []Proposal + + // ProposalByID returns the proposal associated with + // the given ID, if any + ProposalByID(id uint64) (Proposal, error) + + // Size returns the number of proposals in + // the proposal store + Size() int +} + +// Proposal is the single proposal abstraction +type Proposal interface { + // Author returns the author of the proposal + Author() std.Address + + // Description returns the description of the proposal + Description() string + + // Status returns the status of the proposal + Status() ProposalStatus + + // Executor returns the proposal executor + Executor() Executor + + // Stats returns the voting stats of the proposal + Stats() Stats + + // IsExpired returns a flag indicating if the proposal expired + IsExpired() bool + + // Render renders the proposal in a readable format + Render() string +} diff --git a/examples/gno.land/p/demo/dao/vote.gno b/examples/gno.land/p/demo/dao/vote.gno new file mode 100644 index 00000000000..94369f41e1b --- /dev/null +++ b/examples/gno.land/p/demo/dao/vote.gno @@ -0,0 +1,69 @@ +package dao + +// NOTE: +// This voting pods will be removed in a future version of the +// p/demo/dao package. A DAO shouldn't have to comply with or define how the voting mechanism works internally; +// it should be viewed as an entity that makes decisions +// +// The extent of "votes being enforced" in this implementation is just in the context +// of types a DAO can use (import), and in the context of "Stats", where +// there is a notion of "Yay", "Nay" and "Abstain" votes. +const ( + VoteAddedEvent = "VoteAdded" // emitted when a vote was cast for a proposal + + VoteAddedIDKey = "proposal-id" + VoteAddedAuthorKey = "author" + VoteAddedOptionKey = "option" +) + +// VoteOption is the limited voting option for a DAO proposal +type VoteOption string + +const ( + YesVote VoteOption = "YES" // Proposal should be accepted + NoVote VoteOption = "NO" // Proposal should be rejected + AbstainVote VoteOption = "ABSTAIN" // Side is not chosen +) + +func (v VoteOption) String() string { + return string(v) +} + +// Stats encompasses the proposal voting stats +type Stats struct { + YayVotes uint64 + NayVotes uint64 + AbstainVotes uint64 + + TotalVotingPower uint64 +} + +// YayPercent returns the percentage (0-100) of the yay votes +// in relation to the total voting power +func (v Stats) YayPercent() uint64 { + return v.YayVotes * 100 / v.TotalVotingPower +} + +// NayPercent returns the percentage (0-100) of the nay votes +// in relation to the total voting power +func (v Stats) NayPercent() uint64 { + return v.NayVotes * 100 / v.TotalVotingPower +} + +// AbstainPercent returns the percentage (0-100) of the abstain votes +// in relation to the total voting power +func (v Stats) AbstainPercent() uint64 { + return v.AbstainVotes * 100 / v.TotalVotingPower +} + +// MissingVotes returns the summed voting power that has not +// participated in proposal voting yet +func (v Stats) MissingVotes() uint64 { + return v.TotalVotingPower - (v.YayVotes + v.NayVotes + v.AbstainVotes) +} + +// MissingVotesPercent returns the percentage (0-100) of the missing votes +// in relation to the total voting power +func (v Stats) MissingVotesPercent() uint64 { + return v.MissingVotes() * 100 / v.TotalVotingPower +} diff --git a/examples/gno.land/r/gov/dao/gno.mod b/examples/gno.land/p/demo/membstore/gno.mod similarity index 54% rename from examples/gno.land/r/gov/dao/gno.mod rename to examples/gno.land/p/demo/membstore/gno.mod index f3c0bae990e..da22a8dcae4 100644 --- a/examples/gno.land/r/gov/dao/gno.mod +++ b/examples/gno.land/p/demo/membstore/gno.mod @@ -1,8 +1,9 @@ -module gno.land/r/gov/dao +module gno.land/p/demo/membstore require ( + gno.land/p/demo/avl 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 gno.land/p/demo/urequire v0.0.0-latest - gno.land/p/gov/proposal v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/membstore/members.gno b/examples/gno.land/p/demo/membstore/members.gno new file mode 100644 index 00000000000..0bbaaaa8b04 --- /dev/null +++ b/examples/gno.land/p/demo/membstore/members.gno @@ -0,0 +1,38 @@ +package membstore + +import ( + "std" +) + +// MemberStore defines the member storage abstraction +type MemberStore interface { + // Members returns all members in the store + Members(offset, count uint64) []Member + + // Size returns the current size of the store + Size() int + + // IsMember returns a flag indicating if the given address + // belongs to a member + IsMember(address std.Address) bool + + // TotalPower returns the total voting power of the member store + TotalPower() uint64 + + // Member returns the requested member + Member(address std.Address) (Member, error) + + // AddMember adds a member to the store + AddMember(member Member) error + + // UpdateMember updates the member in the store. + // If updating a member's voting power to 0, + // the member will be removed + UpdateMember(address std.Address, member Member) error +} + +// Member holds the relevant member information +type Member struct { + Address std.Address // bech32 gno address of the member (unique) + VotingPower uint64 // the voting power of the member +} diff --git a/examples/gno.land/p/demo/membstore/membstore.gno b/examples/gno.land/p/demo/membstore/membstore.gno new file mode 100644 index 00000000000..6e1932978d9 --- /dev/null +++ b/examples/gno.land/p/demo/membstore/membstore.gno @@ -0,0 +1,209 @@ +package membstore + +import ( + "errors" + "std" + + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + +var ( + ErrAlreadyMember = errors.New("address is already a member") + ErrMissingMember = errors.New("address is not a member") + ErrInvalidAddressUpdate = errors.New("invalid address update") + ErrNotGovDAO = errors.New("caller not correct govdao instance") +) + +// maxRequestMembers is the maximum number of +// paginated members that can be requested +const maxRequestMembers = 50 + +type Option func(*MembStore) + +// WithInitialMembers initializes the member store +// with an initial member list +func WithInitialMembers(members []Member) Option { + return func(store *MembStore) { + for _, m := range members { + memberAddr := m.Address.String() + + // Check if the member already exists + if store.members.Has(memberAddr) { + panic(ufmt.Errorf("%s, %s", memberAddr, ErrAlreadyMember)) + } + + store.members.Set(memberAddr, m) + store.totalVotingPower += m.VotingPower + } + } +} + +// WithDAOPkgPath initializes the member store +// with a dao package path guard +func WithDAOPkgPath(daoPkgPath string) Option { + return func(store *MembStore) { + store.daoPkgPath = daoPkgPath + } +} + +// MembStore implements the dao.MembStore abstraction +type MembStore struct { + daoPkgPath string // active dao pkg path, if any + members *avl.Tree // std.Address -> Member + totalVotingPower uint64 // cached value for quick lookups +} + +// NewMembStore creates a new member store +func NewMembStore(opts ...Option) *MembStore { + m := &MembStore{ + members: avl.NewTree(), // empty set + daoPkgPath: "", // no dao guard + totalVotingPower: 0, + } + + // Apply the options + for _, opt := range opts { + opt(m) + } + + return m +} + +// AddMember adds member to the member store `m`. +// It fails if the caller is not GovDAO or +// if the member is already present +func (m *MembStore) AddMember(member Member) error { + if !m.isCallerDAORealm() { + return ErrNotGovDAO + } + + // Check if the member exists + if m.IsMember(member.Address) { + return ErrAlreadyMember + } + + // Add the member + m.members.Set(member.Address.String(), member) + + // Update the total voting power + m.totalVotingPower += member.VotingPower + + return nil +} + +// UpdateMember updates the member with the given address. +// Updating fails if the caller is not GovDAO. +func (m *MembStore) UpdateMember(address std.Address, member Member) error { + if !m.isCallerDAORealm() { + return ErrNotGovDAO + } + + // Get the member + oldMember, err := m.Member(address) + if err != nil { + return err + } + + // Check if this is a removal request + if member.VotingPower == 0 { + m.members.Remove(address.String()) + + // Update the total voting power + m.totalVotingPower -= oldMember.VotingPower + + return nil + } + + // Check that the member wouldn't be + // overwriting an existing one + isAddressUpdate := address != member.Address + if isAddressUpdate && m.IsMember(member.Address) { + return ErrInvalidAddressUpdate + } + + // Remove the old member info + // in case the address changed + if address != member.Address { + m.members.Remove(address.String()) + } + + // Save the new member info + m.members.Set(member.Address.String(), member) + + // Update the total voting power + difference := member.VotingPower - oldMember.VotingPower + m.totalVotingPower += difference + + return nil +} + +// IsMember returns a flag indicating if the given +// address belongs to a member of the member store +func (m *MembStore) IsMember(address std.Address) bool { + _, exists := m.members.Get(address.String()) + + return exists +} + +// Member returns the member associated with the given address +func (m *MembStore) Member(address std.Address) (Member, error) { + member, exists := m.members.Get(address.String()) + if !exists { + return Member{}, ErrMissingMember + } + + return member.(Member), nil +} + +// Members returns a paginated list of members from +// the member store. If the store is empty, an empty slice +// is returned instead +func (m *MembStore) Members(offset, count uint64) []Member { + // Calculate the left and right bounds + if count < 1 || offset >= uint64(m.members.Size()) { + return []Member{} + } + + // Limit the maximum number of returned members + if count > maxRequestMembers { + count = maxRequestMembers + } + + // Gather the members + members := make([]Member, 0) + m.members.IterateByOffset( + int(offset), + int(count), + func(_ string, val interface{}) bool { + member := val.(Member) + + // Save the member + members = append(members, member) + + return false + }) + + return members +} + +// Size returns the number of active members in the member store +func (m *MembStore) Size() int { + return m.members.Size() +} + +// TotalPower returns the total voting power +// of the member store +func (m *MembStore) TotalPower() uint64 { + return m.totalVotingPower +} + +// isCallerDAORealm returns a flag indicating if the +// current caller context is the active DAO Realm. +// We need to include a dao guard, even if the +// executor guarantees it, because +// the API of the member store is public and callable +// by anyone who has a reference to the member store instance. +func (m *MembStore) isCallerDAORealm() bool { + return m.daoPkgPath == "" || std.CurrentRealm().PkgPath() == m.daoPkgPath +} diff --git a/examples/gno.land/p/demo/membstore/membstore_test.gno b/examples/gno.land/p/demo/membstore/membstore_test.gno new file mode 100644 index 00000000000..2181adde077 --- /dev/null +++ b/examples/gno.land/p/demo/membstore/membstore_test.gno @@ -0,0 +1,317 @@ +package membstore + +import ( + "testing" + + "std" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/p/demo/ufmt" + "gno.land/p/demo/urequire" +) + +// generateMembers generates dummy govdao members +func generateMembers(t *testing.T, count int) []Member { + t.Helper() + + members := make([]Member, 0, count) + + for i := 0; i < count; i++ { + members = append(members, Member{ + Address: testutils.TestAddress(ufmt.Sprintf("member %d", i)), + VotingPower: 10, + }) + } + + return members +} + +func TestMembStore_GetMember(t *testing.T) { + t.Parallel() + + t.Run("member not found", func(t *testing.T) { + t.Parallel() + + // Create an empty store + m := NewMembStore() + + _, err := m.Member(testutils.TestAddress("random")) + uassert.ErrorIs(t, err, ErrMissingMember) + }) + + t.Run("valid member fetched", func(t *testing.T) { + t.Parallel() + + // Create a non-empty store + members := generateMembers(t, 1) + + m := NewMembStore(WithInitialMembers(members)) + + _, err := m.Member(members[0].Address) + uassert.NoError(t, err) + }) +} + +func TestMembStore_GetMembers(t *testing.T) { + t.Parallel() + + t.Run("no members", func(t *testing.T) { + t.Parallel() + + // Create an empty store + m := NewMembStore() + + members := m.Members(0, 10) + uassert.Equal(t, 0, len(members)) + }) + + t.Run("proper pagination", func(t *testing.T) { + t.Parallel() + + var ( + numMembers = maxRequestMembers * 2 + halfRange = numMembers / 2 + + members = generateMembers(t, numMembers) + m = NewMembStore(WithInitialMembers(members)) + + verifyMembersPresent = func(members, fetchedMembers []Member) { + for _, fetchedMember := range fetchedMembers { + for _, member := range members { + if member.Address != fetchedMember.Address { + continue + } + + uassert.Equal(t, member.VotingPower, fetchedMember.VotingPower) + } + } + } + ) + + urequire.Equal(t, numMembers, m.Size()) + + fetchedMembers := m.Members(0, uint64(halfRange)) + urequire.Equal(t, halfRange, len(fetchedMembers)) + + // Verify the members + verifyMembersPresent(members, fetchedMembers) + + // Fetch the other half + fetchedMembers = m.Members(uint64(halfRange), uint64(halfRange)) + urequire.Equal(t, halfRange, len(fetchedMembers)) + + // Verify the members + verifyMembersPresent(members, fetchedMembers) + }) +} + +func TestMembStore_IsMember(t *testing.T) { + t.Parallel() + + t.Run("non-existing member", func(t *testing.T) { + t.Parallel() + + // Create an empty store + m := NewMembStore() + + uassert.False(t, m.IsMember(testutils.TestAddress("random"))) + }) + + t.Run("existing member", func(t *testing.T) { + t.Parallel() + + // Create a non-empty store + members := generateMembers(t, 50) + + m := NewMembStore(WithInitialMembers(members)) + + for _, member := range members { + uassert.True(t, m.IsMember(member.Address)) + } + }) +} + +func TestMembStore_AddMember(t *testing.T) { + t.Parallel() + + t.Run("caller not govdao", func(t *testing.T) { + t.Parallel() + + // Create an empty store + m := NewMembStore(WithDAOPkgPath("gno.land/r/gov/dao")) + + // Attempt to add a member + member := generateMembers(t, 1)[0] + uassert.ErrorIs(t, m.AddMember(member), ErrNotGovDAO) + }) + + t.Run("member already exists", func(t *testing.T) { + t.Parallel() + + var ( + // Execute as the /r/gov/dao caller + daoPkgPath = "gno.land/r/gov/dao" + r = std.NewCodeRealm(daoPkgPath) + ) + + std.TestSetRealm(r) + + // Create a non-empty store + members := generateMembers(t, 1) + m := NewMembStore(WithDAOPkgPath(daoPkgPath), WithInitialMembers(members)) + + // Attempt to add a member + uassert.ErrorIs(t, m.AddMember(members[0]), ErrAlreadyMember) + }) + + t.Run("new member added", func(t *testing.T) { + t.Parallel() + + var ( + // Execute as the /r/gov/dao caller + daoPkgPath = "gno.land/r/gov/dao" + r = std.NewCodeRealm(daoPkgPath) + ) + + std.TestSetRealm(r) + + // Create an empty store + members := generateMembers(t, 1) + m := NewMembStore(WithDAOPkgPath(daoPkgPath)) + + // Attempt to add a member + urequire.NoError(t, m.AddMember(members[0])) + + // Make sure the member is added + uassert.True(t, m.IsMember(members[0].Address)) + }) +} + +func TestMembStore_Size(t *testing.T) { + t.Parallel() + + t.Run("empty govdao", func(t *testing.T) { + t.Parallel() + + // Create an empty store + m := NewMembStore() + + uassert.Equal(t, 0, m.Size()) + }) + + t.Run("non-empty govdao", func(t *testing.T) { + t.Parallel() + + // Create a non-empty store + members := generateMembers(t, 50) + m := NewMembStore(WithInitialMembers(members)) + + uassert.Equal(t, len(members), m.Size()) + }) +} + +func TestMembStore_UpdateMember(t *testing.T) { + t.Parallel() + + t.Run("caller not govdao", func(t *testing.T) { + t.Parallel() + + // Create an empty store + m := NewMembStore(WithDAOPkgPath("gno.land/r/gov/dao")) + + // Attempt to update a member + member := generateMembers(t, 1)[0] + uassert.ErrorIs(t, m.UpdateMember(member.Address, member), ErrNotGovDAO) + }) + + t.Run("non-existing member", func(t *testing.T) { + t.Parallel() + + var ( + // Execute as the /r/gov/dao caller + daoPkgPath = "gno.land/r/gov/dao" + r = std.NewCodeRealm(daoPkgPath) + ) + + std.TestSetRealm(r) + + // Create an empty store + members := generateMembers(t, 1) + m := NewMembStore(WithDAOPkgPath(daoPkgPath)) + + // Attempt to update a member + uassert.ErrorIs(t, m.UpdateMember(members[0].Address, members[0]), ErrMissingMember) + }) + + t.Run("overwrite member attempt", func(t *testing.T) { + t.Parallel() + + var ( + // Execute as the /r/gov/dao caller + daoPkgPath = "gno.land/r/gov/dao" + r = std.NewCodeRealm(daoPkgPath) + ) + + std.TestSetRealm(r) + + // Create a non-empty store + members := generateMembers(t, 2) + m := NewMembStore(WithDAOPkgPath(daoPkgPath), WithInitialMembers(members)) + + // Attempt to update a member + uassert.ErrorIs(t, m.UpdateMember(members[0].Address, members[1]), ErrInvalidAddressUpdate) + }) + + t.Run("successful update", func(t *testing.T) { + t.Parallel() + + var ( + // Execute as the /r/gov/dao caller + daoPkgPath = "gno.land/r/gov/dao" + r = std.NewCodeRealm(daoPkgPath) + ) + + std.TestSetRealm(r) + + // Create a non-empty store + members := generateMembers(t, 1) + m := NewMembStore(WithDAOPkgPath(daoPkgPath), WithInitialMembers(members)) + + oldVotingPower := m.totalVotingPower + urequire.Equal(t, members[0].VotingPower, oldVotingPower) + + votingPower := uint64(300) + members[0].VotingPower = votingPower + + // Attempt to update a member + uassert.NoError(t, m.UpdateMember(members[0].Address, members[0])) + uassert.Equal(t, votingPower, m.Members(0, 10)[0].VotingPower) + urequire.Equal(t, votingPower, m.totalVotingPower) + }) + + t.Run("member removed", func(t *testing.T) { + t.Parallel() + + var ( + // Execute as the /r/gov/dao caller + daoPkgPath = "gno.land/r/gov/dao" + r = std.NewCodeRealm(daoPkgPath) + ) + + std.TestSetRealm(r) + + // Create a non-empty store + members := generateMembers(t, 1) + m := NewMembStore(WithDAOPkgPath(daoPkgPath), WithInitialMembers(members)) + + votingPower := uint64(0) + members[0].VotingPower = votingPower + + // Attempt to update a member + uassert.NoError(t, m.UpdateMember(members[0].Address, members[0])) + + // Make sure the member was removed + uassert.False(t, m.IsMember(members[0].Address)) + }) +} diff --git a/examples/gno.land/p/demo/simpledao/dao.gno b/examples/gno.land/p/demo/simpledao/dao.gno new file mode 100644 index 00000000000..7a20237ec3f --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/dao.gno @@ -0,0 +1,215 @@ +package simpledao + +import ( + "errors" + "std" + + "gno.land/p/demo/avl" + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" + "gno.land/p/demo/ufmt" +) + +var ( + ErrInvalidExecutor = errors.New("invalid executor provided") + ErrInsufficientProposalFunds = errors.New("insufficient funds for proposal") + ErrInsufficientExecuteFunds = errors.New("insufficient funds for executing proposal") + ErrProposalExecuted = errors.New("proposal already executed") + ErrProposalInactive = errors.New("proposal is inactive") + ErrProposalNotAccepted = errors.New("proposal is not accepted") +) + +var ( + minProposalFeeValue int64 = 100 * 1_000_000 // minimum gnot required for a govdao proposal (100 GNOT) + minExecuteFeeValue int64 = 500 * 1_000_000 // minimum gnot required for a govdao proposal (500 GNOT) + + minProposalFee = std.NewCoin("ugnot", minProposalFeeValue) + minExecuteFee = std.NewCoin("ugnot", minExecuteFeeValue) +) + +// SimpleDAO is a simple DAO implementation +type SimpleDAO struct { + proposals *avl.Tree // seqid.ID -> proposal + membStore membstore.MemberStore +} + +// New creates a new instance of the simpledao DAO +func New(membStore membstore.MemberStore) *SimpleDAO { + return &SimpleDAO{ + proposals: avl.NewTree(), + membStore: membStore, + } +} + +func (s *SimpleDAO) Propose(request dao.ProposalRequest) (uint64, error) { + // Make sure the executor is set + if request.Executor == nil { + return 0, ErrInvalidExecutor + } + + var ( + caller = getDAOCaller() + sentCoins = std.GetOrigSend() // Get the sent coins, if any + canCoverFee = sentCoins.AmountOf("ugnot") >= minProposalFee.Amount + ) + + // Check if the proposal is valid + if !s.membStore.IsMember(caller) && !canCoverFee { + return 0, ErrInsufficientProposalFunds + } + + // Create the wrapped proposal + prop := &proposal{ + author: caller, + description: request.Description, + executor: request.Executor, + status: dao.Active, + tally: newTally(), + getTotalVotingPowerFn: s.membStore.TotalPower, + } + + // Add the proposal + id, err := s.addProposal(prop) + if err != nil { + return 0, ufmt.Errorf("unable to add proposal, %s", err.Error()) + } + + // Emit the proposal added event + dao.EmitProposalAdded(id, caller) + + return id, nil +} + +func (s *SimpleDAO) VoteOnProposal(id uint64, option dao.VoteOption) error { + // Verify the GOVDAO member + caller := getDAOCaller() + + member, err := s.membStore.Member(caller) + if err != nil { + return ufmt.Errorf("unable to get govdao member, %s", err.Error()) + } + + // Check if the proposal exists + propRaw, err := s.ProposalByID(id) + if err != nil { + return ufmt.Errorf("unable to get proposal %d, %s", id, err.Error()) + } + + prop := propRaw.(*proposal) + + // Check the proposal status + if prop.Status() == dao.ExecutionSuccessful || + prop.Status() == dao.ExecutionFailed { + // Proposal was already executed, nothing to vote on anymore. + // + // In fact, the proposal should stop accepting + // votes as soon as a 2/3+ majority is reached + // on either option, but leaving the ability to vote still, + // even if a proposal is accepted, or not accepted, + // leaves room for "principle" vote decisions to be recorded + return ErrProposalInactive + } + + // Cast the vote + if err = prop.tally.castVote(member, option); err != nil { + return ufmt.Errorf("unable to vote on proposal %d, %s", id, err.Error()) + } + + // Emit the vote cast event + dao.EmitVoteAdded(id, caller, option) + + // Check the votes to see if quorum is reached + var ( + totalPower = s.membStore.TotalPower() + majorityPower = (2 * totalPower) / 3 + ) + + acceptProposal := func() { + prop.status = dao.Accepted + + dao.EmitProposalAccepted(id) + } + + declineProposal := func() { + prop.status = dao.NotAccepted + + dao.EmitProposalNotAccepted(id) + } + + switch { + case prop.tally.yays > majorityPower: + // 2/3+ voted YES + acceptProposal() + case prop.tally.nays > majorityPower: + // 2/3+ voted NO + declineProposal() + case prop.tally.abstains > majorityPower: + // 2/3+ voted ABSTAIN + declineProposal() + case prop.tally.yays+prop.tally.nays+prop.tally.abstains >= totalPower: + // Everyone voted, but it's undecided, + // hence the proposal can't go through + declineProposal() + default: + // Quorum not reached + } + + return nil +} + +func (s *SimpleDAO) ExecuteProposal(id uint64) error { + var ( + caller = getDAOCaller() + sentCoins = std.GetOrigSend() // Get the sent coins, if any + canCoverFee = sentCoins.AmountOf("ugnot") >= minExecuteFee.Amount + ) + + // Check if the non-DAO member can cover the execute fee + if !s.membStore.IsMember(caller) && !canCoverFee { + return ErrInsufficientExecuteFunds + } + + // Check if the proposal exists + propRaw, err := s.ProposalByID(id) + if err != nil { + return ufmt.Errorf("unable to get proposal %d, %s", id, err.Error()) + } + + prop := propRaw.(*proposal) + + // Check if the proposal is executed + if prop.Status() == dao.ExecutionSuccessful || + prop.Status() == dao.ExecutionFailed { + // Proposal is already executed + return ErrProposalExecuted + } + + // Check the proposal status + if prop.Status() != dao.Accepted { + // Proposal is not accepted, cannot be executed + return ErrProposalNotAccepted + } + + // Emit an event when the execution finishes + defer dao.EmitProposalExecuted(id, prop.status) + + // Attempt to execute the proposal + if err = prop.executor.Execute(); err != nil { + prop.status = dao.ExecutionFailed + + return ufmt.Errorf("error during proposal %d execution, %s", id, err.Error()) + } + + // Update the proposal status + prop.status = dao.ExecutionSuccessful + + return nil +} + +// getDAOCaller returns the DAO caller. +// XXX: This is not a great way to determine the caller, and it is very unsafe. +// However, the current MsgRun context does not persist escaping the main() scope. +// Until a better solution is developed, this enables proposals to be made through a package deployment + init() +func getDAOCaller() std.Address { + return std.GetOrigCaller() +} diff --git a/examples/gno.land/p/demo/simpledao/dao_test.gno b/examples/gno.land/p/demo/simpledao/dao_test.gno new file mode 100644 index 00000000000..fb32895e72f --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/dao_test.gno @@ -0,0 +1,829 @@ +package simpledao + +import ( + "errors" + "std" + "testing" + + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/p/demo/ufmt" + "gno.land/p/demo/urequire" +) + +// generateMembers generates dummy govdao members +func generateMembers(t *testing.T, count int) []membstore.Member { + t.Helper() + + members := make([]membstore.Member, 0, count) + + for i := 0; i < count; i++ { + members = append(members, membstore.Member{ + Address: testutils.TestAddress(ufmt.Sprintf("member %d", i)), + VotingPower: 10, + }) + } + + return members +} + +func TestSimpleDAO_Propose(t *testing.T) { + t.Parallel() + + t.Run("invalid executor", func(t *testing.T) { + t.Parallel() + + s := New(nil) + + _, err := s.Propose(dao.ProposalRequest{}) + uassert.ErrorIs( + t, + err, + ErrInvalidExecutor, + ) + }) + + t.Run("caller cannot cover fee", func(t *testing.T) { + t.Parallel() + + var ( + called = false + cb = func() error { + called = true + + return nil + } + ex = &mockExecutor{ + executeFn: cb, + } + + sentCoins = std.NewCoins( + std.NewCoin( + "ugnot", + minProposalFeeValue-1, + ), + ) + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return false + }, + } + s = New(ms) + ) + + // Set the sent coins to be lower + // than the proposal fee + std.TestSetOrigSend(sentCoins, std.Coins{}) + + _, err := s.Propose(dao.ProposalRequest{ + Executor: ex, + }) + uassert.ErrorIs( + t, + err, + ErrInsufficientProposalFunds, + ) + + uassert.False(t, called) + }) + + t.Run("proposal added", func(t *testing.T) { + t.Parallel() + + var ( + called = false + cb = func() error { + called = true + + return nil + } + + ex = &mockExecutor{ + executeFn: cb, + } + description = "Proposal description" + + proposer = testutils.TestAddress("proposer") + sentCoins = std.NewCoins( + std.NewCoin( + "ugnot", + minProposalFeeValue, // enough to cover + ), + ) + + ms = &mockMemberStore{ + isMemberFn: func(addr std.Address) bool { + return addr == proposer + }, + } + s = New(ms) + ) + + // Set the sent coins to be enough + // to cover the fee + std.TestSetOrigSend(sentCoins, std.Coins{}) + std.TestSetOrigCaller(proposer) + + // Make sure the proposal was added + id, err := s.Propose(dao.ProposalRequest{ + Description: description, + Executor: ex, + }) + uassert.NoError(t, err) + uassert.False(t, called) + + // Make sure the proposal exists + prop, err := s.ProposalByID(id) + uassert.NoError(t, err) + + uassert.Equal(t, proposer.String(), prop.Author().String()) + uassert.Equal(t, description, prop.Description()) + uassert.Equal(t, dao.Active.String(), prop.Status().String()) + + stats := prop.Stats() + + uassert.Equal(t, uint64(0), stats.YayVotes) + uassert.Equal(t, uint64(0), stats.NayVotes) + uassert.Equal(t, uint64(0), stats.AbstainVotes) + uassert.Equal(t, uint64(0), stats.TotalVotingPower) + }) +} + +func TestSimpleDAO_VoteOnProposal(t *testing.T) { + t.Parallel() + + t.Run("not govdao member", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + fetchErr = errors.New("fetch error") + + ms = &mockMemberStore{ + memberFn: func(_ std.Address) (membstore.Member, error) { + return membstore.Member{ + Address: voter, + }, fetchErr + }, + } + s = New(ms) + ) + + std.TestSetOrigCaller(voter) + + // Attempt to vote on the proposal + uassert.ErrorContains( + t, + s.VoteOnProposal(0, dao.YesVote), + fetchErr.Error(), + ) + }) + + t.Run("missing proposal", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + ms = &mockMemberStore{ + memberFn: func(a std.Address) (membstore.Member, error) { + if a != voter { + return membstore.Member{}, errors.New("not found") + } + + return membstore.Member{ + Address: voter, + }, nil + }, + } + + s = New(ms) + ) + + std.TestSetOrigCaller(voter) + + // Attempt to vote on the proposal + uassert.ErrorContains( + t, + s.VoteOnProposal(0, dao.YesVote), + ErrMissingProposal.Error(), + ) + }) + + t.Run("proposal executed", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + + ms = &mockMemberStore{ + memberFn: func(a std.Address) (membstore.Member, error) { + if a != voter { + return membstore.Member{}, errors.New("not found") + } + + return membstore.Member{ + Address: voter, + }, nil + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.ExecutionSuccessful, + } + ) + + std.TestSetOrigCaller(voter) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // Attempt to vote on the proposal + uassert.ErrorIs( + t, + s.VoteOnProposal(id, dao.YesVote), + ErrProposalInactive, + ) + }) + + t.Run("double vote on proposal", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + member = membstore.Member{ + Address: voter, + VotingPower: 10, + } + + ms = &mockMemberStore{ + memberFn: func(a std.Address) (membstore.Member, error) { + if a != voter { + return membstore.Member{}, errors.New("not found") + } + + return member, nil + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.Active, + executor: &mockExecutor{}, + tally: newTally(), + } + ) + + std.TestSetOrigCaller(voter) + + // Cast the initial vote + urequire.NoError(t, prop.tally.castVote(member, dao.YesVote)) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // Attempt to vote on the proposal + uassert.ErrorContains( + t, + s.VoteOnProposal(id, dao.YesVote), + ErrAlreadyVoted.Error(), + ) + }) + + t.Run("majority accepted", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + + ms = &mockMemberStore{ + memberFn: func(address std.Address) (membstore.Member, error) { + for _, m := range members { + if m.Address == address { + return m, nil + } + } + + return membstore.Member{}, errors.New("not found") + }, + + totalPowerFn: func() uint64 { + power := uint64(0) + + for _, m := range members { + power += m.VotingPower + } + + return power + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.Active, + executor: &mockExecutor{}, + tally: newTally(), + } + ) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + majorityIndex := (len(members)*2)/3 + 1 // 2/3+ + for _, m := range members[:majorityIndex] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.YesVote), + ) + } + + // Make sure the proposal was accepted + uassert.Equal(t, dao.Accepted.String(), prop.status.String()) + }) + + t.Run("majority rejected", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + + ms = &mockMemberStore{ + memberFn: func(address std.Address) (membstore.Member, error) { + for _, m := range members { + if m.Address == address { + return m, nil + } + } + + return membstore.Member{}, errors.New("member not found") + }, + + totalPowerFn: func() uint64 { + power := uint64(0) + + for _, m := range members { + power += m.VotingPower + } + + return power + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.Active, + executor: &mockExecutor{}, + tally: newTally(), + } + ) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + majorityIndex := (len(members)*2)/3 + 1 // 2/3+ + for _, m := range members[:majorityIndex] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.NoVote), + ) + } + + // Make sure the proposal was not accepted + uassert.Equal(t, dao.NotAccepted.String(), prop.status.String()) + }) + + t.Run("majority abstained", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + + ms = &mockMemberStore{ + memberFn: func(address std.Address) (membstore.Member, error) { + for _, m := range members { + if m.Address == address { + return m, nil + } + } + + return membstore.Member{}, errors.New("member not found") + }, + + totalPowerFn: func() uint64 { + power := uint64(0) + + for _, m := range members { + power += m.VotingPower + } + + return power + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.Active, + executor: &mockExecutor{}, + tally: newTally(), + } + ) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + majorityIndex := (len(members)*2)/3 + 1 // 2/3+ + for _, m := range members[:majorityIndex] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.AbstainVote), + ) + } + + // Make sure the proposal was not accepted + uassert.Equal(t, dao.NotAccepted.String(), prop.status.String()) + }) + + t.Run("everyone voted, undecided", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + + ms = &mockMemberStore{ + memberFn: func(address std.Address) (membstore.Member, error) { + for _, m := range members { + if m.Address == address { + return m, nil + } + } + + return membstore.Member{}, errors.New("member not found") + }, + + totalPowerFn: func() uint64 { + power := uint64(0) + + for _, m := range members { + power += m.VotingPower + } + + return power + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.Active, + executor: &mockExecutor{}, + tally: newTally(), + } + ) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // The first half votes yes + for _, m := range members[:len(members)/2] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.YesVote), + ) + } + + // The other half votes no + for _, m := range members[len(members)/2:] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.NoVote), + ) + } + + // Make sure the proposal is not active, + // since everyone voted, and it was undecided + uassert.Equal(t, dao.NotAccepted.String(), prop.status.String()) + }) + + t.Run("proposal undecided", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + + ms = &mockMemberStore{ + memberFn: func(address std.Address) (membstore.Member, error) { + for _, m := range members { + if m.Address == address { + return m, nil + } + } + + return membstore.Member{}, errors.New("member not found") + }, + + totalPowerFn: func() uint64 { + power := uint64(0) + + for _, m := range members { + power += m.VotingPower + } + + return power + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.Active, + executor: &mockExecutor{}, + tally: newTally(), + } + ) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // The first quarter votes yes + for _, m := range members[:len(members)/4] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.YesVote), + ) + } + + // The second quarter votes no + for _, m := range members[len(members)/4 : len(members)/2] { + std.TestSetOrigCaller(m.Address) + + // Attempt to vote on the proposal + urequire.NoError( + t, + s.VoteOnProposal(id, dao.NoVote), + ) + } + + // Make sure the proposal is still active, + // since there wasn't quorum reached on any decision + uassert.Equal(t, dao.Active.String(), prop.status.String()) + }) +} + +func TestSimpleDAO_ExecuteProposal(t *testing.T) { + t.Parallel() + + t.Run("caller cannot cover fee", func(t *testing.T) { + t.Parallel() + + var ( + sentCoins = std.NewCoins( + std.NewCoin( + "ugnot", + minExecuteFeeValue-1, + ), + ) + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return false + }, + } + s = New(ms) + ) + + // Set the sent coins to be lower + // than the execute fee + std.TestSetOrigSend(sentCoins, std.Coins{}) + + uassert.ErrorIs( + t, + s.ExecuteProposal(0), + ErrInsufficientExecuteFunds, + ) + }) + + t.Run("missing proposal", func(t *testing.T) { + t.Parallel() + + var ( + sentCoins = std.NewCoins( + std.NewCoin( + "ugnot", + minExecuteFeeValue, + ), + ) + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return true + }, + } + + s = New(ms) + ) + + // Set the sent coins to be enough + // so the execution can take place + std.TestSetOrigSend(sentCoins, std.Coins{}) + + uassert.ErrorContains( + t, + s.ExecuteProposal(0), + ErrMissingProposal.Error(), + ) + }) + + t.Run("proposal not accepted", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return true + }, + } + s = New(ms) + + prop = &proposal{ + status: dao.NotAccepted, + } + ) + + std.TestSetOrigCaller(voter) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // Attempt to vote on the proposal + uassert.ErrorIs( + t, + s.ExecuteProposal(id), + ErrProposalNotAccepted, + ) + }) + + t.Run("proposal already executed", func(t *testing.T) { + t.Parallel() + + testTable := []struct { + name string + status dao.ProposalStatus + }{ + { + "execution was successful", + dao.ExecutionSuccessful, + }, + { + "execution failed", + dao.ExecutionFailed, + }, + } + + for _, testCase := range testTable { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return true + }, + } + s = New(ms) + + prop = &proposal{ + status: testCase.status, + } + ) + + std.TestSetOrigCaller(voter) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // Attempt to vote on the proposal + uassert.ErrorIs( + t, + s.ExecuteProposal(id), + ErrProposalExecuted, + ) + }) + } + }) + + t.Run("execution error", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return true + }, + } + + s = New(ms) + + execError = errors.New("exec error") + + mockExecutor = &mockExecutor{ + executeFn: func() error { + return execError + }, + } + + prop = &proposal{ + status: dao.Accepted, + executor: mockExecutor, + } + ) + + std.TestSetOrigCaller(voter) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // Attempt to vote on the proposal + uassert.ErrorContains( + t, + s.ExecuteProposal(id), + execError.Error(), + ) + + uassert.Equal(t, dao.ExecutionFailed.String(), prop.status.String()) + }) + + t.Run("successful execution", func(t *testing.T) { + t.Parallel() + + var ( + voter = testutils.TestAddress("voter") + + ms = &mockMemberStore{ + isMemberFn: func(_ std.Address) bool { + return true + }, + } + s = New(ms) + + called = false + mockExecutor = &mockExecutor{ + executeFn: func() error { + called = true + + return nil + }, + } + + prop = &proposal{ + status: dao.Accepted, + executor: mockExecutor, + } + ) + + std.TestSetOrigCaller(voter) + + // Add an initial proposal + id, err := s.addProposal(prop) + urequire.NoError(t, err) + + // Attempt to vote on the proposal + uassert.NoError(t, s.ExecuteProposal(id)) + uassert.Equal(t, dao.ExecutionSuccessful.String(), prop.status.String()) + uassert.True(t, called) + }) +} diff --git a/examples/gno.land/p/demo/simpledao/gno.mod b/examples/gno.land/p/demo/simpledao/gno.mod new file mode 100644 index 00000000000..f6f14f379ec --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/gno.mod @@ -0,0 +1,12 @@ +module gno.land/p/demo/simpledao + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/dao v0.0.0-latest + gno.land/p/demo/membstore v0.0.0-latest + gno.land/p/demo/seqid 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 + gno.land/p/demo/urequire v0.0.0-latest +) diff --git a/examples/gno.land/p/demo/simpledao/mock_test.gno b/examples/gno.land/p/demo/simpledao/mock_test.gno new file mode 100644 index 00000000000..0cf12ccff01 --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/mock_test.gno @@ -0,0 +1,97 @@ +package simpledao + +import ( + "std" + + "gno.land/p/demo/membstore" +) + +type executeDelegate func() error + +type mockExecutor struct { + executeFn executeDelegate +} + +func (m *mockExecutor) Execute() error { + if m.executeFn != nil { + return m.executeFn() + } + + return nil +} + +type ( + membersDelegate func(uint64, uint64) []membstore.Member + sizeDelegate func() int + isMemberDelegate func(std.Address) bool + totalPowerDelegate func() uint64 + memberDelegate func(std.Address) (membstore.Member, error) + addMemberDelegate func(membstore.Member) error + updateMemberDelegate func(std.Address, membstore.Member) error +) + +type mockMemberStore struct { + membersFn membersDelegate + sizeFn sizeDelegate + isMemberFn isMemberDelegate + totalPowerFn totalPowerDelegate + memberFn memberDelegate + addMemberFn addMemberDelegate + updateMemberFn updateMemberDelegate +} + +func (m *mockMemberStore) Members(offset, count uint64) []membstore.Member { + if m.membersFn != nil { + return m.membersFn(offset, count) + } + + return nil +} + +func (m *mockMemberStore) Size() int { + if m.sizeFn != nil { + return m.sizeFn() + } + + return 0 +} + +func (m *mockMemberStore) IsMember(address std.Address) bool { + if m.isMemberFn != nil { + return m.isMemberFn(address) + } + + return false +} + +func (m *mockMemberStore) TotalPower() uint64 { + if m.totalPowerFn != nil { + return m.totalPowerFn() + } + + return 0 +} + +func (m *mockMemberStore) Member(address std.Address) (membstore.Member, error) { + if m.memberFn != nil { + return m.memberFn(address) + } + + return membstore.Member{}, nil +} + +func (m *mockMemberStore) AddMember(member membstore.Member) error { + if m.addMemberFn != nil { + return m.addMemberFn(member) + } + + return nil +} + +func (m *mockMemberStore) UpdateMember(address std.Address, member membstore.Member) error { + if m.updateMemberFn != nil { + return m.updateMemberFn(address, member) + } + + return nil +} diff --git a/examples/gno.land/p/demo/simpledao/propstore.gno b/examples/gno.land/p/demo/simpledao/propstore.gno new file mode 100644 index 00000000000..972297ff0ce --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/propstore.gno @@ -0,0 +1,163 @@ +package simpledao + +import ( + "errors" + "std" + + "gno.land/p/demo/dao" + "gno.land/p/demo/seqid" + "gno.land/p/demo/ufmt" +) + +var ErrMissingProposal = errors.New("proposal is missing") + +// maxRequestProposals is the maximum number of +// paginated proposals that can be requested +const maxRequestProposals = 10 + +// proposal is the internal simpledao proposal implementation +type proposal struct { + author std.Address // initiator of the proposal + description string // description of the proposal + + executor dao.Executor // executor for the proposal + status dao.ProposalStatus // status of the proposal + + tally *tally // voting tally + getTotalVotingPowerFn func() uint64 // callback for the total voting power +} + +func (p *proposal) Author() std.Address { + return p.author +} + +func (p *proposal) Description() string { + return p.description +} + +func (p *proposal) Status() dao.ProposalStatus { + return p.status +} + +func (p *proposal) Executor() dao.Executor { + return p.executor +} + +func (p *proposal) Stats() dao.Stats { + // Get the total voting power of the body + totalPower := p.getTotalVotingPowerFn() + + return dao.Stats{ + YayVotes: p.tally.yays, + NayVotes: p.tally.nays, + AbstainVotes: p.tally.abstains, + TotalVotingPower: totalPower, + } +} + +func (p *proposal) IsExpired() bool { + return false // this proposal never expires +} + +func (p *proposal) Render() string { + // Fetch the voting stats + stats := p.Stats() + + output := "" + output += ufmt.Sprintf("Author: %s", p.Author().String()) + output += "\n\n" + output += p.Description() + output += "\n\n" + output += ufmt.Sprintf("Status: %s", p.Status().String()) + output += "\n\n" + output += ufmt.Sprintf( + "Voting stats: YAY %d (%d%%), NAY %d (%d%%), ABSTAIN %d (%d%%), HAVEN'T VOTED %d (%d%%)", + stats.YayVotes, + stats.YayPercent(), + stats.NayVotes, + stats.NayPercent(), + stats.AbstainVotes, + stats.AbstainPercent(), + stats.MissingVotes(), + stats.MissingVotesPercent(), + ) + output += "\n\n" + output += ufmt.Sprintf("Threshold met: %t", stats.YayVotes > (2*stats.TotalVotingPower)/3) + + return output +} + +// addProposal adds a new simpledao proposal to the store +func (s *SimpleDAO) addProposal(proposal *proposal) (uint64, error) { + // See what the next proposal number should be + nextID := uint64(s.proposals.Size()) + + // Save the proposal + s.proposals.Set(getProposalID(nextID), proposal) + + return nextID, nil +} + +func (s *SimpleDAO) Proposals(offset, count uint64) []dao.Proposal { + // Check the requested count + if count < 1 { + return []dao.Proposal{} + } + + // Limit the maximum number of returned proposals + if count > maxRequestProposals { + count = maxRequestProposals + } + + var ( + startIndex = offset + endIndex = startIndex + count + + numProposals = uint64(s.proposals.Size()) + ) + + // Check if the current offset has any proposals + if startIndex >= numProposals { + return []dao.Proposal{} + } + + // Check if the right bound is good + if endIndex > numProposals { + endIndex = numProposals + } + + props := make([]dao.Proposal, 0) + s.proposals.Iterate( + getProposalID(startIndex), + getProposalID(endIndex), + func(_ string, val interface{}) bool { + prop := val.(*proposal) + + // Save the proposal + props = append(props, prop) + + return false + }, + ) + + return props +} + +func (s *SimpleDAO) ProposalByID(id uint64) (dao.Proposal, error) { + prop, exists := s.proposals.Get(getProposalID(id)) + if !exists { + return nil, ErrMissingProposal + } + + return prop.(*proposal), nil +} + +func (s *SimpleDAO) Size() int { + return s.proposals.Size() +} + +// getProposalID generates a sequential proposal ID +// from the given ID number +func getProposalID(id uint64) string { + return seqid.ID(id).String() +} diff --git a/examples/gno.land/p/demo/simpledao/propstore_test.gno b/examples/gno.land/p/demo/simpledao/propstore_test.gno new file mode 100644 index 00000000000..5aa6ba91a1e --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/propstore_test.gno @@ -0,0 +1,256 @@ +package simpledao + +import ( + "testing" + + "gno.land/p/demo/dao" + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/p/demo/ufmt" + "gno.land/p/demo/urequire" +) + +// generateProposals generates dummy proposals +func generateProposals(t *testing.T, count int) []*proposal { + t.Helper() + + var ( + members = generateMembers(t, count) + proposals = make([]*proposal, 0, count) + ) + + for i := 0; i < count; i++ { + proposal := &proposal{ + author: members[i].Address, + description: ufmt.Sprintf("proposal %d", i), + status: dao.Active, + tally: newTally(), + getTotalVotingPowerFn: func() uint64 { + return 0 + }, + executor: nil, + } + + proposals = append(proposals, proposal) + } + + return proposals +} + +func equalProposals(t *testing.T, p1, p2 dao.Proposal) { + t.Helper() + + uassert.Equal( + t, + p1.Author().String(), + p2.Author().String(), + ) + + uassert.Equal( + t, + p1.Description(), + p2.Description(), + ) + + uassert.Equal( + t, + p1.Status().String(), + p2.Status().String(), + ) + + p1Stats := p1.Stats() + p2Stats := p2.Stats() + + uassert.Equal(t, p1Stats.YayVotes, p2Stats.YayVotes) + uassert.Equal(t, p1Stats.NayVotes, p2Stats.NayVotes) + uassert.Equal(t, p1Stats.AbstainVotes, p2Stats.AbstainVotes) + uassert.Equal(t, p1Stats.TotalVotingPower, p2Stats.TotalVotingPower) +} + +func TestProposal_Data(t *testing.T) { + t.Parallel() + + t.Run("author", func(t *testing.T) { + t.Parallel() + + p := &proposal{ + author: testutils.TestAddress("address"), + } + + uassert.Equal(t, p.author, p.Author()) + }) + + t.Run("description", func(t *testing.T) { + t.Parallel() + + p := &proposal{ + description: "example proposal description", + } + + uassert.Equal(t, p.description, p.Description()) + }) + + t.Run("status", func(t *testing.T) { + t.Parallel() + + p := &proposal{ + status: dao.ExecutionSuccessful, + } + + uassert.Equal(t, p.status.String(), p.Status().String()) + }) + + t.Run("executor", func(t *testing.T) { + t.Parallel() + + var ( + numCalled = 0 + cb = func() error { + numCalled++ + + return nil + } + + ex = &mockExecutor{ + executeFn: cb, + } + + p = &proposal{ + executor: ex, + } + ) + + urequire.NoError(t, p.executor.Execute()) + urequire.NoError(t, p.Executor().Execute()) + + uassert.Equal(t, 2, numCalled) + }) + + t.Run("no votes", func(t *testing.T) { + t.Parallel() + + p := &proposal{ + tally: newTally(), + getTotalVotingPowerFn: func() uint64 { + return 0 + }, + } + + stats := p.Stats() + + uassert.Equal(t, uint64(0), stats.YayVotes) + uassert.Equal(t, uint64(0), stats.NayVotes) + uassert.Equal(t, uint64(0), stats.AbstainVotes) + uassert.Equal(t, uint64(0), stats.TotalVotingPower) + }) + + t.Run("existing votes", func(t *testing.T) { + t.Parallel() + + var ( + members = generateMembers(t, 50) + totalPower = uint64(len(members)) * 10 + + p = &proposal{ + tally: newTally(), + getTotalVotingPowerFn: func() uint64 { + return totalPower + }, + } + ) + + for _, m := range members { + urequire.NoError(t, p.tally.castVote(m, dao.YesVote)) + } + + stats := p.Stats() + + uassert.Equal(t, totalPower, stats.YayVotes) + uassert.Equal(t, uint64(0), stats.NayVotes) + uassert.Equal(t, uint64(0), stats.AbstainVotes) + uassert.Equal(t, totalPower, stats.TotalVotingPower) + }) +} + +func TestSimpleDAO_GetProposals(t *testing.T) { + t.Parallel() + + t.Run("no proposals", func(t *testing.T) { + t.Parallel() + + s := New(nil) + + uassert.Equal(t, 0, s.Size()) + proposals := s.Proposals(0, 0) + + uassert.Equal(t, 0, len(proposals)) + }) + + t.Run("proper pagination", func(t *testing.T) { + t.Parallel() + + var ( + numProposals = 20 + halfRange = numProposals / 2 + + s = New(nil) + proposals = generateProposals(t, numProposals) + ) + + // Add initial proposals + for _, proposal := range proposals { + _, err := s.addProposal(proposal) + + urequire.NoError(t, err) + } + + uassert.Equal(t, numProposals, s.Size()) + + fetchedProposals := s.Proposals(0, uint64(halfRange)) + urequire.Equal(t, halfRange, len(fetchedProposals)) + + for index, fetchedProposal := range fetchedProposals { + equalProposals(t, proposals[index], fetchedProposal) + } + + // Fetch the other half + fetchedProposals = s.Proposals(uint64(halfRange), uint64(halfRange)) + urequire.Equal(t, halfRange, len(fetchedProposals)) + + for index, fetchedProposal := range fetchedProposals { + equalProposals(t, proposals[index+halfRange], fetchedProposal) + } + }) +} + +func TestSimpleDAO_GetProposalByID(t *testing.T) { + t.Parallel() + + t.Run("missing proposal", func(t *testing.T) { + t.Parallel() + + s := New(nil) + + _, err := s.ProposalByID(0) + uassert.ErrorIs(t, err, ErrMissingProposal) + }) + + t.Run("proposal found", func(t *testing.T) { + t.Parallel() + + var ( + s = New(nil) + proposal = generateProposals(t, 1)[0] + ) + + // Add the initial proposal + _, err := s.addProposal(proposal) + urequire.NoError(t, err) + + // Fetch the proposal + fetchedProposal, err := s.ProposalByID(0) + urequire.NoError(t, err) + + equalProposals(t, proposal, fetchedProposal) + }) +} diff --git a/examples/gno.land/p/demo/simpledao/votestore.gno b/examples/gno.land/p/demo/simpledao/votestore.gno new file mode 100644 index 00000000000..35a6564a1e3 --- /dev/null +++ b/examples/gno.land/p/demo/simpledao/votestore.gno @@ -0,0 +1,55 @@ +package simpledao + +import ( + "errors" + + "gno.land/p/demo/avl" + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" +) + +var ErrAlreadyVoted = errors.New("vote already cast") + +// tally is a simple vote tally system +type tally struct { + // tally cache to keep track of active + // yes / no / abstain votes + yays uint64 + nays uint64 + abstains uint64 + + voters *avl.Tree // std.Address -> dao.VoteOption +} + +// newTally creates a new tally system instance +func newTally() *tally { + return &tally{ + voters: avl.NewTree(), + } +} + +// castVote casts a single vote in the name of the given member +func (t *tally) castVote(member membstore.Member, option dao.VoteOption) error { + // Check if the member voted already + address := member.Address.String() + + _, voted := t.voters.Get(address) + if voted { + return ErrAlreadyVoted + } + + // Update the tally + switch option { + case dao.YesVote: + t.yays += member.VotingPower + case dao.AbstainVote: + t.abstains += member.VotingPower + default: + t.nays += member.VotingPower + } + + // Save the voting status + t.voters.Set(address, option) + + return nil +} diff --git a/examples/gno.land/p/gov/executor/callback.gno b/examples/gno.land/p/gov/executor/callback.gno new file mode 100644 index 00000000000..5d46a97cd69 --- /dev/null +++ b/examples/gno.land/p/gov/executor/callback.gno @@ -0,0 +1,39 @@ +package executor + +import ( + "errors" + "std" +) + +var errInvalidCaller = errors.New("invalid executor caller") + +// NewCallbackExecutor creates a new callback executor with the provided callback function +func NewCallbackExecutor(callback func() error, path string) *CallbackExecutor { + return &CallbackExecutor{ + callback: callback, + daoPkgPath: path, + } +} + +// CallbackExecutor is an implementation of the dao.Executor interface, +// based on a specific callback. +// The given callback should verify the validity of the govdao call +type CallbackExecutor struct { + callback func() error // the callback to be executed + daoPkgPath string // the active pkg path of the govdao +} + +// Execute runs the executor's callback function. +func (exec *CallbackExecutor) Execute() error { + // Verify the caller is an adequate Realm + caller := std.CurrentRealm().PkgPath() + if caller != exec.daoPkgPath { + return errInvalidCaller + } + + if exec.callback != nil { + return exec.callback() + } + + return nil +} diff --git a/examples/gno.land/p/gov/executor/context.gno b/examples/gno.land/p/gov/executor/context.gno new file mode 100644 index 00000000000..158e3b1e0be --- /dev/null +++ b/examples/gno.land/p/gov/executor/context.gno @@ -0,0 +1,75 @@ +package executor + +import ( + "errors" + "std" + + "gno.land/p/demo/context" +) + +type propContextKey string + +func (k propContextKey) String() string { return string(k) } + +const ( + statusContextKey = propContextKey("govdao-prop-status") + approvedStatus = "approved" +) + +var errNotApproved = errors.New("not approved by govdao") + +// CtxExecutor is an implementation of the dao.Executor interface, +// based on the given context. +// It utilizes the given context to assert the validity of the govdao call +type CtxExecutor struct { + callbackCtx func(ctx context.Context) error // the callback ctx fn, if any + daoPkgPath string // the active pkg path of the govdao +} + +// NewCtxExecutor creates a new executor with the provided callback function. +func NewCtxExecutor(callback func(ctx context.Context) error, path string) *CtxExecutor { + return &CtxExecutor{ + callbackCtx: callback, + daoPkgPath: path, + } +} + +// Execute runs the executor's callback function +func (exec *CtxExecutor) Execute() error { + // Verify the caller is an adequate Realm + caller := std.CurrentRealm().PkgPath() + if caller != exec.daoPkgPath { + return errInvalidCaller + } + + // Create the context + ctx := context.WithValue( + context.Empty(), + statusContextKey, + approvedStatus, + ) + + return exec.callbackCtx(ctx) +} + +// IsApprovedByGovdaoContext asserts that the govdao approved the context +func IsApprovedByGovdaoContext(ctx context.Context) bool { + v := ctx.Value(statusContextKey) + if v == nil { + return false + } + + vs, ok := v.(string) + + return ok && vs == approvedStatus +} + +// AssertContextApprovedByGovDAO asserts the given context +// was approved by GOVDAO +func AssertContextApprovedByGovDAO(ctx context.Context) { + if IsApprovedByGovdaoContext(ctx) { + return + } + + panic(errNotApproved) +} diff --git a/examples/gno.land/p/gov/proposal/gno.mod b/examples/gno.land/p/gov/executor/gno.mod similarity index 80% rename from examples/gno.land/p/gov/proposal/gno.mod rename to examples/gno.land/p/gov/executor/gno.mod index 3f6ef34a759..99f2ab3610b 100644 --- a/examples/gno.land/p/gov/proposal/gno.mod +++ b/examples/gno.land/p/gov/executor/gno.mod @@ -1,4 +1,4 @@ -module gno.land/p/gov/proposal +module gno.land/p/gov/executor require ( gno.land/p/demo/context v0.0.0-latest diff --git a/examples/gno.land/p/gov/executor/proposal_test.gno b/examples/gno.land/p/gov/executor/proposal_test.gno new file mode 100644 index 00000000000..3a70fc40596 --- /dev/null +++ b/examples/gno.land/p/gov/executor/proposal_test.gno @@ -0,0 +1,180 @@ +package executor + +import ( + "errors" + "std" + "testing" + + "gno.land/p/demo/context" + "gno.land/p/demo/uassert" + "gno.land/p/demo/urequire" +) + +func TestExecutor_Callback(t *testing.T) { + t.Parallel() + + t.Run("govdao not caller", func(t *testing.T) { + t.Parallel() + + var ( + called = false + + cb = func() error { + called = true + + return nil + } + ) + + // Create the executor + e := NewCallbackExecutor(cb, "gno.land/r/gov/dao") + + // Execute as not the /r/gov/dao caller + uassert.ErrorIs(t, e.Execute(), errInvalidCaller) + uassert.False(t, called, "expected proposal to not execute") + }) + + t.Run("execution successful", func(t *testing.T) { + t.Parallel() + + var ( + called = false + + cb = func() error { + called = true + + return nil + } + ) + + // Create the executor + daoPkgPath := "gno.land/r/gov/dao" + e := NewCallbackExecutor(cb, daoPkgPath) + + // Execute as the /r/gov/dao caller + r := std.NewCodeRealm(daoPkgPath) + std.TestSetRealm(r) + + uassert.NoError(t, e.Execute()) + uassert.True(t, called, "expected proposal to execute") + }) + + t.Run("execution unsuccessful", func(t *testing.T) { + t.Parallel() + + var ( + called = false + expectedErr = errors.New("unexpected") + + cb = func() error { + called = true + + return expectedErr + } + ) + + // Create the executor + daoPkgPath := "gno.land/r/gov/dao" + e := NewCallbackExecutor(cb, daoPkgPath) + + // Execute as the /r/gov/dao caller + r := std.NewCodeRealm(daoPkgPath) + std.TestSetRealm(r) + + uassert.ErrorIs(t, e.Execute(), expectedErr) + uassert.True(t, called, "expected proposal to execute") + }) +} + +func TestExecutor_Context(t *testing.T) { + t.Parallel() + + t.Run("govdao not caller", func(t *testing.T) { + t.Parallel() + + var ( + called = false + + cb = func(ctx context.Context) error { + if !IsApprovedByGovdaoContext(ctx) { + t.Fatal("not govdao caller") + } + + called = true + + return nil + } + ) + + // Create the executor + e := NewCtxExecutor(cb, "gno.land/r/gov/dao") + + // Execute as not the /r/gov/dao caller + uassert.ErrorIs(t, e.Execute(), errInvalidCaller) + uassert.False(t, called, "expected proposal to not execute") + }) + + t.Run("execution successful", func(t *testing.T) { + t.Parallel() + + var ( + called = false + + cb = func(ctx context.Context) error { + if !IsApprovedByGovdaoContext(ctx) { + t.Fatal("not govdao caller") + } + + called = true + + return nil + } + ) + + // Create the executor + daoPkgPath := "gno.land/r/gov/dao" + e := NewCtxExecutor(cb, daoPkgPath) + + // Execute as the /r/gov/dao caller + r := std.NewCodeRealm(daoPkgPath) + std.TestSetRealm(r) + + urequire.NoError(t, e.Execute()) + uassert.True(t, called, "expected proposal to execute") + }) + + t.Run("execution unsuccessful", func(t *testing.T) { + t.Parallel() + + var ( + called = false + expectedErr = errors.New("unexpected") + + cb = func(ctx context.Context) error { + if !IsApprovedByGovdaoContext(ctx) { + t.Fatal("not govdao caller") + } + + called = true + + return expectedErr + } + ) + + // Create the executor + daoPkgPath := "gno.land/r/gov/dao" + e := NewCtxExecutor(cb, daoPkgPath) + + // Execute as the /r/gov/dao caller + r := std.NewCodeRealm(daoPkgPath) + std.TestSetRealm(r) + + uassert.NotPanics(t, func() { + err := e.Execute() + + uassert.ErrorIs(t, err, expectedErr) + }) + + uassert.True(t, called, "expected proposal to execute") + }) +} diff --git a/examples/gno.land/p/gov/proposal/proposal.gno b/examples/gno.land/p/gov/proposal/proposal.gno deleted file mode 100644 index ca1767228c9..00000000000 --- a/examples/gno.land/p/gov/proposal/proposal.gno +++ /dev/null @@ -1,106 +0,0 @@ -// Package proposal provides a structure for executing proposals. -package proposal - -import ( - "errors" - "std" - - "gno.land/p/demo/context" -) - -var errNotGovDAO = errors.New("only r/gov/dao can be the caller") - -// NewExecutor creates a new executor with the provided callback function. -func NewExecutor(callback func() error) Executor { - return &executorImpl{ - callback: callback, - done: false, - } -} - -// NewCtxExecutor creates a new executor with the provided callback function. -func NewCtxExecutor(callback func(ctx context.Context) error) Executor { - return &executorImpl{ - callbackCtx: callback, - done: false, - } -} - -// executorImpl is an implementation of the Executor interface. -type executorImpl struct { - callback func() error - callbackCtx func(ctx context.Context) error - done bool - success bool -} - -// Execute runs the executor's callback function. -func (exec *executorImpl) Execute() error { - if exec.done { - return ErrAlreadyDone - } - - // Verify the executor is r/gov/dao - assertCalledByGovdao() - - var err error - if exec.callback != nil { - err = exec.callback() - } else if exec.callbackCtx != nil { - ctx := context.WithValue(context.Empty(), statusContextKey, approvedStatus) - err = exec.callbackCtx(ctx) - } - exec.done = true - exec.success = err == nil - - return err -} - -// IsDone returns whether the executor has been executed. -func (exec *executorImpl) IsDone() bool { - return exec.done -} - -// IsSuccessful returns whether the execution was successful. -func (exec *executorImpl) IsSuccessful() bool { - return exec.success -} - -// IsExpired returns whether the execution had expired or not. -// This implementation never expires. -func (exec *executorImpl) IsExpired() bool { - return false -} - -func IsApprovedByGovdaoContext(ctx context.Context) bool { - v := ctx.Value(statusContextKey) - if v == nil { - return false - } - vs, ok := v.(string) - return ok && vs == approvedStatus -} - -func AssertContextApprovedByGovDAO(ctx context.Context) { - if !IsApprovedByGovdaoContext(ctx) { - panic("not approved by govdao") - } -} - -// assertCalledByGovdao asserts that the calling Realm is /r/gov/dao -func assertCalledByGovdao() { - caller := std.CurrentRealm().PkgPath() - - if caller != daoPkgPath { - panic(errNotGovDAO) - } -} - -type propContextKey string - -func (k propContextKey) String() string { return string(k) } - -const ( - statusContextKey = propContextKey("govdao-prop-status") - approvedStatus = "approved" -) diff --git a/examples/gno.land/p/gov/proposal/proposal_test.gno b/examples/gno.land/p/gov/proposal/proposal_test.gno deleted file mode 100644 index 536871e644d..00000000000 --- a/examples/gno.land/p/gov/proposal/proposal_test.gno +++ /dev/null @@ -1,156 +0,0 @@ -package proposal - -import ( - "errors" - "std" - "testing" - - "gno.land/p/demo/uassert" - "gno.land/p/demo/urequire" -) - -func TestExecutor(t *testing.T) { - t.Parallel() - - verifyProposalFailed := func(e Executor) { - uassert.True(t, e.IsDone(), "expected proposal to be done") - uassert.False(t, e.IsSuccessful(), "expected proposal to fail") - } - - verifyProposalSucceeded := func(e Executor) { - uassert.True(t, e.IsDone(), "expected proposal to be done") - uassert.True(t, e.IsSuccessful(), "expected proposal to be successful") - } - - t.Run("govdao not caller", func(t *testing.T) { - t.Parallel() - - var ( - called = false - - cb = func() error { - called = true - - return nil - } - ) - - // Create the executor - e := NewExecutor(cb) - - urequire.False(t, e.IsDone(), "expected status to be NotExecuted") - - // Execute as not the /r/gov/dao caller - uassert.PanicsWithMessage(t, errNotGovDAO.Error(), func() { - _ = e.Execute() - }) - - uassert.False(t, called, "expected proposal to not execute") - }) - - t.Run("execution successful", func(t *testing.T) { - t.Parallel() - - var ( - called = false - - cb = func() error { - called = true - - return nil - } - ) - - // Create the executor - e := NewExecutor(cb) - - urequire.False(t, e.IsDone(), "expected status to be NotExecuted") - - // Execute as the /r/gov/dao caller - r := std.NewCodeRealm(daoPkgPath) - std.TestSetRealm(r) - - uassert.NotPanics(t, func() { - err := e.Execute() - - uassert.NoError(t, err) - }) - - uassert.True(t, called, "expected proposal to execute") - - // Make sure the execution params are correct - verifyProposalSucceeded(e) - }) - - t.Run("execution unsuccessful", func(t *testing.T) { - t.Parallel() - - var ( - called = false - expectedErr = errors.New("unexpected") - - cb = func() error { - called = true - - return expectedErr - } - ) - - // Create the executor - e := NewExecutor(cb) - - // Execute as the /r/gov/dao caller - r := std.NewCodeRealm(daoPkgPath) - std.TestSetRealm(r) - - uassert.NotPanics(t, func() { - err := e.Execute() - - uassert.ErrorIs(t, err, expectedErr) - }) - - uassert.True(t, called, "expected proposal to execute") - - // Make sure the execution params are correct - verifyProposalFailed(e) - }) - - t.Run("proposal already executed", func(t *testing.T) { - t.Parallel() - - var ( - called = false - - cb = func() error { - called = true - - return nil - } - ) - - // Create the executor - e := NewExecutor(cb) - - urequire.False(t, e.IsDone(), "expected status to be NotExecuted") - - // Execute as the /r/gov/dao caller - r := std.NewCodeRealm(daoPkgPath) - std.TestSetRealm(r) - - uassert.NotPanics(t, func() { - uassert.NoError(t, e.Execute()) - }) - - uassert.True(t, called, "expected proposal to execute") - - // Make sure the execution params are correct - verifyProposalSucceeded(e) - - // Attempt to execute the proposal again - uassert.NotPanics(t, func() { - err := e.Execute() - - uassert.ErrorIs(t, err, ErrAlreadyDone) - }) - }) -} diff --git a/examples/gno.land/p/gov/proposal/types.gno b/examples/gno.land/p/gov/proposal/types.gno deleted file mode 100644 index 6cd2da9ccfe..00000000000 --- a/examples/gno.land/p/gov/proposal/types.gno +++ /dev/null @@ -1,37 +0,0 @@ -// Package proposal defines types for proposal execution. -package proposal - -import "errors" - -// Executor represents a minimal closure-oriented proposal design. -// It is intended to be used by a govdao governance proposal (v1, v2, etc). -type Executor interface { - // Execute executes the given proposal, and returns any error encountered - // during the execution - Execute() error - - // IsDone returns a flag indicating if the proposal was executed - IsDone() bool - - // IsSuccessful returns a flag indicating if the proposal was executed - // and is successful - IsSuccessful() bool // IsDone() && !err - - // IsExpired returns whether the execution had expired or not. - IsExpired() bool -} - -// ErrAlreadyDone is the error returned when trying to execute an already -// executed proposal. -var ErrAlreadyDone = errors.New("already executed") - -// Status enum. -type Status string - -const ( - NotExecuted Status = "not_executed" - Succeeded Status = "succeeded" - Failed Status = "failed" -) - -const daoPkgPath = "gno.land/r/gov/dao" // TODO: make sure this is configurable through r/sys/vars diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 08b0911cf24..9c94a265fca 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -5,8 +5,8 @@ import ( "strings" "gno.land/p/demo/avl" - "gno.land/p/demo/context" - "gno.land/p/gov/proposal" + "gno.land/p/demo/dao" + "gno.land/r/gov/dao/bridge" ) var ( @@ -41,10 +41,14 @@ func AdminRemoveModerator(addr std.Address) { moderatorList.Set(addr.String(), false) // FIXME: delete instead? } -func DaoAddPost(ctx context.Context, slug, title, body, publicationDate, authors, tags string) { - proposal.AssertContextApprovedByGovDAO(ctx) - caller := std.DerivePkgAddr("gno.land/r/gov/dao") - addPost(caller, slug, title, body, publicationDate, authors, tags) +func NewPostExecutor(slug, title, body, publicationDate, authors, tags string) dao.Executor { + callback := func() error { + addPost(std.PrevRealm().Addr(), slug, title, body, publicationDate, authors, tags) + + return nil + } + + return bridge.GovDAO().NewGovDAOExecutor(callback) } func ModAddPost(slug, title, body, publicationDate, authors, tags string) { diff --git a/examples/gno.land/r/gnoland/blog/gno.mod b/examples/gno.land/r/gnoland/blog/gno.mod index 17c17e0cfa6..8a4c5851b4c 100644 --- a/examples/gno.land/r/gnoland/blog/gno.mod +++ b/examples/gno.land/r/gnoland/blog/gno.mod @@ -3,6 +3,6 @@ module gno.land/r/gnoland/blog require ( gno.land/p/demo/avl v0.0.0-latest gno.land/p/demo/blog v0.0.0-latest - gno.land/p/demo/context v0.0.0-latest - gno.land/p/gov/proposal v0.0.0-latest + gno.land/p/demo/dao v0.0.0-latest + gno.land/r/gov/dao/bridge 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 93f9a68f39a..57570902f5a 100644 --- a/examples/gno.land/r/gnoland/home/home.gno +++ b/examples/gno.land/r/gnoland/home/home.gno @@ -193,7 +193,7 @@ func packageStaffPicks() ui.Element { ui.BulletList{ ui.Link{URL: "r/sys/names"}, ui.Link{URL: "r/sys/rewards"}, - ui.Link{URL: "r/sys/validators"}, + ui.Link{URL: "/r/sys/validators/v2"}, }, }, { ui.H4("[r/demo](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo)"), diff --git a/examples/gno.land/r/gnoland/home/home_filetest.gno b/examples/gno.land/r/gnoland/home/home_filetest.gno index 2260dc3a409..89721fd8d08 100644 --- a/examples/gno.land/r/gnoland/home/home_filetest.gno +++ b/examples/gno.land/r/gnoland/home/home_filetest.gno @@ -117,7 +117,7 @@ func main() { // // - [r/sys/names](r/sys/names) // - [r/sys/rewards](r/sys/rewards) -// - [r/sys/validators](r/sys/validators) +// - [/r/sys/validators/v2](/r/sys/validators/v2) // //
//
diff --git a/examples/gno.land/r/gnoland/valopers/gno.mod b/examples/gno.land/r/gnoland/valopers/v2/gno.mod similarity index 56% rename from examples/gno.land/r/gnoland/valopers/gno.mod rename to examples/gno.land/r/gnoland/valopers/v2/gno.mod index 2d24fb27952..099a8406db4 100644 --- a/examples/gno.land/r/gnoland/valopers/gno.mod +++ b/examples/gno.land/r/gnoland/valopers/v2/gno.mod @@ -1,11 +1,12 @@ -module gno.land/r/gnoland/valopers +module gno.land/r/gnoland/valopers/v2 require ( gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/dao 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 gno.land/p/sys/validators v0.0.0-latest - gno.land/r/gov/dao v0.0.0-latest - gno.land/r/sys/validators v0.0.0-latest + gno.land/r/gov/dao/bridge v0.0.0-latest + gno.land/r/sys/validators/v2 v0.0.0-latest ) diff --git a/examples/gno.land/r/gnoland/valopers/init.gno b/examples/gno.land/r/gnoland/valopers/v2/init.gno similarity index 100% rename from examples/gno.land/r/gnoland/valopers/init.gno rename to examples/gno.land/r/gnoland/valopers/v2/init.gno diff --git a/examples/gno.land/r/gnoland/valopers/valopers.gno b/examples/gno.land/r/gnoland/valopers/v2/valopers.gno similarity index 90% rename from examples/gno.land/r/gnoland/valopers/valopers.gno rename to examples/gno.land/r/gnoland/valopers/v2/valopers.gno index 74cec941e0d..d88ea4b872f 100644 --- a/examples/gno.land/r/gnoland/valopers/valopers.gno +++ b/examples/gno.land/r/gnoland/valopers/v2/valopers.gno @@ -6,10 +6,11 @@ import ( "std" "gno.land/p/demo/avl" + "gno.land/p/demo/dao" "gno.land/p/demo/ufmt" pVals "gno.land/p/sys/validators" - govdao "gno.land/r/gov/dao" - "gno.land/r/sys/validators" + "gno.land/r/gov/dao/bridge" + validators "gno.land/r/sys/validators/v2" ) const ( @@ -25,6 +26,7 @@ var valopers *avl.Tree // Address -> Valoper // Valoper represents a validator operator profile type Valoper struct { Name string // the display name of the valoper + Moniker string // the moniker of the valoper Description string // the description of the valoper Address std.Address // The bech32 gno address of the validator @@ -101,7 +103,7 @@ func Render(_ string) string { // Render renders a single valoper with their information func (v Valoper) Render() string { - output := ufmt.Sprintf("## %s\n", v.Name) + output := ufmt.Sprintf("## %s (%s)\n", v.Name, v.Moniker) output += ufmt.Sprintf("%s\n\n", v.Description) output += ufmt.Sprintf("- Address: %s\n", v.Address.String()) output += ufmt.Sprintf("- PubKey: %s\n", v.PubKey) @@ -168,14 +170,19 @@ func GovDAOProposal(address std.Address) { // Create the executor executor := validators.NewPropExecutor(changesFn) - // Craft the proposal comment - comment := ufmt.Sprintf( - "Proposal to add valoper %s (Address: %s; PubKey: %s) to the valset", + // Craft the proposal description + description := ufmt.Sprintf( + "Add valoper %s (Address: %s; PubKey: %s) to the valset", valoper.Name, valoper.Address.String(), valoper.PubKey, ) + prop := dao.ProposalRequest{ + Description: description, + Executor: executor, + } + // Create the govdao proposal - govdao.Propose(comment, executor) + bridge.GovDAO().Propose(prop) } diff --git a/examples/gno.land/r/gnoland/valopers/valopers_test.gno b/examples/gno.land/r/gnoland/valopers/v2/valopers_test.gno similarity index 97% rename from examples/gno.land/r/gnoland/valopers/valopers_test.gno rename to examples/gno.land/r/gnoland/valopers/v2/valopers_test.gno index 89544c46ee5..b5940738769 100644 --- a/examples/gno.land/r/gnoland/valopers/valopers_test.gno +++ b/examples/gno.land/r/gnoland/valopers/v2/valopers_test.gno @@ -38,6 +38,7 @@ func TestValopers_Register(t *testing.T) { v := Valoper{ Address: testutils.TestAddress("valoper"), Name: "new valoper", + Moniker: "val-1", PubKey: "pub key", } @@ -50,6 +51,7 @@ func TestValopers_Register(t *testing.T) { uassert.Equal(t, v.Address, valoper.Address) uassert.Equal(t, v.Name, valoper.Name) + uassert.Equal(t, v.Moniker, valoper.Moniker) uassert.Equal(t, v.PubKey, valoper.PubKey) }) }) diff --git a/examples/gno.land/r/gov/dao/bridge/bridge.gno b/examples/gno.land/r/gov/dao/bridge/bridge.gno new file mode 100644 index 00000000000..ba47978f33f --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/bridge.gno @@ -0,0 +1,39 @@ +package bridge + +import ( + "std" + + "gno.land/p/demo/ownable" +) + +const initialOwner = std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq") // @moul + +var b *Bridge + +// Bridge is the active GovDAO +// implementation bridge +type Bridge struct { + *ownable.Ownable + + dao DAO +} + +// init constructs the initial GovDAO implementation +func init() { + b = &Bridge{ + Ownable: ownable.NewWithAddress(initialOwner), + dao: &govdaoV2{}, + } +} + +// SetDAO sets the currently active GovDAO implementation +func SetDAO(dao DAO) { + b.AssertCallerIsOwner() + + b.dao = dao +} + +// GovDAO returns the current GovDAO implementation +func GovDAO() DAO { + return b.dao +} diff --git a/examples/gno.land/r/gov/dao/bridge/bridge_test.gno b/examples/gno.land/r/gov/dao/bridge/bridge_test.gno new file mode 100644 index 00000000000..38b5d4be257 --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/bridge_test.gno @@ -0,0 +1,64 @@ +package bridge + +import ( + "testing" + + "std" + + "gno.land/p/demo/dao" + "gno.land/p/demo/ownable" + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/p/demo/urequire" +) + +func TestBridge_DAO(t *testing.T) { + var ( + proposalID = uint64(10) + mockDAO = &mockDAO{ + proposeFn: func(_ dao.ProposalRequest) uint64 { + return proposalID + }, + } + ) + + b.dao = mockDAO + + uassert.Equal(t, proposalID, GovDAO().Propose(dao.ProposalRequest{})) +} + +func TestBridge_SetDAO(t *testing.T) { + t.Run("invalid owner", func(t *testing.T) { + // Attempt to set a new DAO implementation + uassert.PanicsWithMessage(t, ownable.ErrUnauthorized.Error(), func() { + SetDAO(&mockDAO{}) + }) + }) + + t.Run("valid owner", func(t *testing.T) { + var ( + addr = testutils.TestAddress("owner") + + proposalID = uint64(10) + mockDAO = &mockDAO{ + proposeFn: func(_ dao.ProposalRequest) uint64 { + return proposalID + }, + } + ) + + std.TestSetOrigCaller(addr) + + b.Ownable = ownable.NewWithAddress(addr) + + urequire.NotPanics(t, func() { + SetDAO(mockDAO) + }) + + uassert.Equal( + t, + mockDAO.Propose(dao.ProposalRequest{}), + GovDAO().Propose(dao.ProposalRequest{}), + ) + }) +} diff --git a/examples/gno.land/r/gov/dao/bridge/doc.gno b/examples/gno.land/r/gov/dao/bridge/doc.gno new file mode 100644 index 00000000000..f812b3c0787 --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/doc.gno @@ -0,0 +1,4 @@ +// Package bridge represents a GovDAO implementation wrapper, used by other Realms and Packages to +// always fetch the most active GovDAO implementation, instead of directly referencing it, and having to +// update it each time the GovDAO implementation changes +package bridge diff --git a/examples/gno.land/r/gov/dao/bridge/gno.mod b/examples/gno.land/r/gov/dao/bridge/gno.mod new file mode 100644 index 00000000000..3382557573a --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/gno.mod @@ -0,0 +1,11 @@ +module gno.land/r/gov/dao/bridge + +require ( + gno.land/p/demo/dao v0.0.0-latest + gno.land/p/demo/membstore 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/urequire v0.0.0-latest + gno.land/r/gov/dao/v2 v0.0.0-latest +) diff --git a/examples/gno.land/r/gov/dao/bridge/mock_test.gno b/examples/gno.land/r/gov/dao/bridge/mock_test.gno new file mode 100644 index 00000000000..05ac430b4c4 --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/mock_test.gno @@ -0,0 +1,68 @@ +package bridge + +import ( + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" +) + +type ( + proposeDelegate func(dao.ProposalRequest) uint64 + voteOnProposalDelegate func(uint64, dao.VoteOption) + executeProposalDelegate func(uint64) + getPropStoreDelegate func() dao.PropStore + getMembStoreDelegate func() membstore.MemberStore + newGovDAOExecutorDelegate func(func() error) dao.Executor +) + +type mockDAO struct { + proposeFn proposeDelegate + voteOnProposalFn voteOnProposalDelegate + executeProposalFn executeProposalDelegate + getPropStoreFn getPropStoreDelegate + getMembStoreFn getMembStoreDelegate + newGovDAOExecutorFn newGovDAOExecutorDelegate +} + +func (m *mockDAO) Propose(request dao.ProposalRequest) uint64 { + if m.proposeFn != nil { + return m.proposeFn(request) + } + + return 0 +} + +func (m *mockDAO) VoteOnProposal(id uint64, option dao.VoteOption) { + if m.voteOnProposalFn != nil { + m.voteOnProposalFn(id, option) + } +} + +func (m *mockDAO) ExecuteProposal(id uint64) { + if m.executeProposalFn != nil { + m.executeProposalFn(id) + } +} + +func (m *mockDAO) GetPropStore() dao.PropStore { + if m.getPropStoreFn != nil { + return m.getPropStoreFn() + } + + return nil +} + +func (m *mockDAO) GetMembStore() membstore.MemberStore { + if m.getMembStoreFn != nil { + return m.getMembStoreFn() + } + + return nil +} + +func (m *mockDAO) NewGovDAOExecutor(cb func() error) dao.Executor { + if m.newGovDAOExecutorFn != nil { + return m.newGovDAOExecutorFn(cb) + } + + return nil +} diff --git a/examples/gno.land/r/gov/dao/bridge/types.gno b/examples/gno.land/r/gov/dao/bridge/types.gno new file mode 100644 index 00000000000..27ea8fb62d4 --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/types.gno @@ -0,0 +1,17 @@ +package bridge + +import ( + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" +) + +// DAO abstracts the commonly used DAO interface +type DAO interface { + Propose(dao.ProposalRequest) uint64 + VoteOnProposal(uint64, dao.VoteOption) + ExecuteProposal(uint64) + GetPropStore() dao.PropStore + GetMembStore() membstore.MemberStore + + NewGovDAOExecutor(func() error) dao.Executor +} diff --git a/examples/gno.land/r/gov/dao/bridge/v2.gno b/examples/gno.land/r/gov/dao/bridge/v2.gno new file mode 100644 index 00000000000..216419cf31d --- /dev/null +++ b/examples/gno.land/r/gov/dao/bridge/v2.gno @@ -0,0 +1,42 @@ +package bridge + +import ( + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" + govdao "gno.land/r/gov/dao/v2" +) + +// govdaoV2 is a wrapper for interacting with the /r/gov/dao/v2 Realm +type govdaoV2 struct{} + +func (g *govdaoV2) Propose(request dao.ProposalRequest) uint64 { + return govdao.Propose(request) +} + +func (g *govdaoV2) VoteOnProposal(id uint64, option dao.VoteOption) { + govdao.VoteOnProposal(id, option) +} + +func (g *govdaoV2) ExecuteProposal(id uint64) { + govdao.ExecuteProposal(id) +} + +func (g *govdaoV2) GetPropStore() dao.PropStore { + return govdao.GetPropStore() +} + +func (g *govdaoV2) GetMembStore() membstore.MemberStore { + return govdao.GetMembStore() +} + +func (g *govdaoV2) NewGovDAOExecutor(cb func() error) dao.Executor { + return govdao.NewGovDAOExecutor(cb) +} + +func (g *govdaoV2) NewMemberPropExecutor(cb func() []membstore.Member) dao.Executor { + return govdao.NewMemberPropExecutor(cb) +} + +func (g *govdaoV2) NewMembStoreImplExecutor(cb func() membstore.MemberStore) dao.Executor { + return govdao.NewMembStoreImplExecutor(cb) +} diff --git a/examples/gno.land/r/gov/dao/dao.gno b/examples/gno.land/r/gov/dao/dao.gno deleted file mode 100644 index 632935dafed..00000000000 --- a/examples/gno.land/r/gov/dao/dao.gno +++ /dev/null @@ -1,207 +0,0 @@ -package govdao - -import ( - "std" - "strconv" - - "gno.land/p/demo/ufmt" - pproposal "gno.land/p/gov/proposal" -) - -var ( - proposals = make([]*proposal, 0) - members = make([]std.Address, 0) // XXX: these should be pointers to avoid data duplication. Not possible due to VM bugs -) - -const ( - msgMissingExecutor = "missing proposal executor" - msgPropExecuted = "prop already executed" - msgPropExpired = "prop is expired" - msgPropInactive = "prop is not active anymore" - msgPropActive = "prop is still active" - msgPropNotAccepted = "prop is not accepted" - - msgCallerNotAMember = "caller is not member of govdao" - msgProposalNotFound = "proposal not found" -) - -type proposal struct { - author std.Address - comment string - executor pproposal.Executor - voter Voter - executed bool - voters []std.Address // XXX: these should be pointers to avoid data duplication. Not possible due to VM bugs. -} - -func (p proposal) Status() Status { - if p.executor.IsExpired() { - return Expired - } - - if p.executor.IsDone() { - return Succeeded - } - - if !p.voter.IsFinished(members) { - return Active - } - - if p.voter.IsAccepted(members) { - return Accepted - } - - return NotAccepted -} - -// Propose is designed to be called by another contract or with -// `maketx run`, not by a `maketx call`. -func Propose(comment string, executor pproposal.Executor) int { - // XXX: require payment? - if executor == nil { - panic(msgMissingExecutor) - } - caller := std.GetOrigCaller() // XXX: CHANGE THIS WHEN MSGRUN PERSIST CODE ESCAPING THE main() SCOPE! IT IS UNSAFE! - AssertIsMember(caller) - - prop := &proposal{ - comment: comment, - executor: executor, - author: caller, - voter: NewPercentageVoter(66), // at least 2/3 must say yes - } - - proposals = append(proposals, prop) - - return len(proposals) - 1 -} - -func VoteOnProposal(idx int, option string) { - assertProposalExists(idx) - caller := std.GetOrigCaller() // XXX: CHANGE THIS WHEN MSGRUN PERSIST CODE ESCAPING THE main() SCOPE! IT IS UNSAFE! - AssertIsMember(caller) - - prop := getProposal(idx) - - if prop.executed { - panic(msgPropExecuted) - } - - if prop.executor.IsExpired() { - panic(msgPropExpired) - } - - if prop.voter.IsFinished(members) { - panic(msgPropInactive) - } - - prop.voter.Vote(members, caller, option) -} - -func ExecuteProposal(idx int) { - assertProposalExists(idx) - prop := getProposal(idx) - - if prop.executed { - panic(msgPropExecuted) - } - - if prop.executor.IsExpired() { - panic(msgPropExpired) - } - - if !prop.voter.IsFinished(members) { - panic(msgPropActive) - } - - if !prop.voter.IsAccepted(members) { - panic(msgPropNotAccepted) - } - - prop.executor.Execute() - prop.voters = members - prop.executed = true -} - -func IsMember(addr std.Address) bool { - if len(members) == 0 { // special case for initial execution - return true - } - - for _, v := range members { - if v == addr { - return true - } - } - - return false -} - -func AssertIsMember(addr std.Address) { - if !IsMember(addr) { - panic(msgCallerNotAMember) - } -} - -func Render(path string) string { - if path == "" { - if len(proposals) == 0 { - return "No proposals found :(" // corner case - } - - output := "" - for idx, prop := range proposals { - output += ufmt.Sprintf("- [%d](/r/gov/dao:%d) - %s (**%s**)(by %s)\n", idx, idx, prop.comment, string(prop.Status()), prop.author) - } - - return output - } - - // else display the proposal - idx, err := strconv.Atoi(path) - if err != nil { - return "404" - } - - if !proposalExists(idx) { - return "404" - } - prop := getProposal(idx) - - vs := members - if prop.executed { - vs = prop.voters - } - - output := "" - output += ufmt.Sprintf("# Prop #%d", idx) - output += "\n\n" - output += prop.comment - output += "\n\n" - output += ufmt.Sprintf("Status: %s", string(prop.Status())) - output += "\n\n" - output += ufmt.Sprintf("Voting status: %s", prop.voter.Status(vs)) - output += "\n\n" - output += ufmt.Sprintf("Author: %s", string(prop.author)) - output += "\n\n" - - return output -} - -func getProposal(idx int) *proposal { - if idx > len(proposals)-1 { - panic(msgProposalNotFound) - } - - return proposals[idx] -} - -func proposalExists(idx int) bool { - return idx >= 0 && idx <= len(proposals) -} - -func assertProposalExists(idx int) { - if !proposalExists(idx) { - panic("invalid proposal id") - } -} diff --git a/examples/gno.land/r/gov/dao/dao_test.gno b/examples/gno.land/r/gov/dao/dao_test.gno deleted file mode 100644 index 96eaba7f5e9..00000000000 --- a/examples/gno.land/r/gov/dao/dao_test.gno +++ /dev/null @@ -1,192 +0,0 @@ -package govdao - -import ( - "std" - "testing" - - "gno.land/p/demo/testutils" - "gno.land/p/demo/urequire" - pproposal "gno.land/p/gov/proposal" -) - -func TestPackage(t *testing.T) { - u1 := testutils.TestAddress("u1") - u2 := testutils.TestAddress("u2") - u3 := testutils.TestAddress("u3") - - members = append(members, u1) - members = append(members, u2) - members = append(members, u3) - - nu1 := testutils.TestAddress("random1") - - out := Render("") - - expected := "No proposals found :(" - urequire.Equal(t, expected, out) - - var called bool - ex := pproposal.NewExecutor(func() error { - called = true - return nil - }) - - std.TestSetOrigCaller(u1) - pid := Propose("dummy proposal", ex) - - // try to vote not being a member - std.TestSetOrigCaller(nu1) - - urequire.PanicsWithMessage(t, msgCallerNotAMember, func() { - VoteOnProposal(pid, "YES") - }) - - // try to vote several times - std.TestSetOrigCaller(u1) - urequire.NotPanics(t, func() { - VoteOnProposal(pid, "YES") - }) - urequire.PanicsWithMessage(t, msgAlreadyVoted, func() { - VoteOnProposal(pid, "YES") - }) - - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: active - -Voting status: YES: 1, NO: 0, percent: 33, members: 3 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - - std.TestSetOrigCaller(u2) - urequire.PanicsWithMessage(t, msgWrongVotingValue, func() { - VoteOnProposal(pid, "INCORRECT") - }) - urequire.NotPanics(t, func() { - VoteOnProposal(pid, "NO") - }) - - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: active - -Voting status: YES: 1, NO: 1, percent: 33, members: 3 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - - std.TestSetOrigCaller(u3) - urequire.NotPanics(t, func() { - VoteOnProposal(pid, "YES") - }) - - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: accepted - -Voting status: YES: 2, NO: 1, percent: 66, members: 3 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - - // Add a new member, so non-executed proposals will change the voting status - u4 := testutils.TestAddress("u4") - members = append(members, u4) - - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: active - -Voting status: YES: 2, NO: 1, percent: 50, members: 4 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - - std.TestSetOrigCaller(u4) - urequire.NotPanics(t, func() { - VoteOnProposal(pid, "YES") - }) - - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: accepted - -Voting status: YES: 3, NO: 1, percent: 75, members: 4 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - - ExecuteProposal(pid) - urequire.True(t, called) - - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: succeeded - -Voting status: YES: 3, NO: 1, percent: 75, members: 4 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - - // Add a new member and try to vote an already executed proposal - u5 := testutils.TestAddress("u5") - members = append(members, u5) - std.TestSetOrigCaller(u5) - urequire.PanicsWithMessage(t, msgPropExecuted, func() { - ExecuteProposal(pid) - }) - - // even if we added a new member the executed proposal is showing correctly the members that voted on it - out = Render("0") - expected = `# Prop #0 - -dummy proposal - -Status: succeeded - -Voting status: YES: 3, NO: 1, percent: 75, members: 4 - -Author: g1w5c47h6lta047h6lta047h6lta047h6ly5kscr - -` - - urequire.Equal(t, expected, out) - -} diff --git a/examples/gno.land/r/gov/dao/memberset.gno b/examples/gno.land/r/gov/dao/memberset.gno deleted file mode 100644 index 3abd52ae99d..00000000000 --- a/examples/gno.land/r/gov/dao/memberset.gno +++ /dev/null @@ -1,40 +0,0 @@ -package govdao - -import ( - "std" - - pproposal "gno.land/p/gov/proposal" -) - -const daoPkgPath = "gno.land/r/gov/dao" - -const ( - errNoChangesProposed = "no set changes proposed" - errNotGovDAO = "caller not govdao executor" -) - -func NewPropExecutor(changesFn func() []std.Address) pproposal.Executor { - if changesFn == nil { - panic(errNoChangesProposed) - } - - callback := func() error { - // Make sure the GovDAO executor runs the valset changes - assertGovDAOCaller() - - for _, addr := range changesFn() { - members = append(members, addr) - } - - return nil - } - - return pproposal.NewExecutor(callback) -} - -// assertGovDAOCaller verifies the caller is the GovDAO executor -func assertGovDAOCaller() { - if std.CurrentRealm().PkgPath() != daoPkgPath { - panic(errNotGovDAO) - } -} diff --git a/examples/gno.land/r/gov/dao/prop2_filetest.gno b/examples/gno.land/r/gov/dao/prop2_filetest.gno deleted file mode 100644 index 047709cc45f..00000000000 --- a/examples/gno.land/r/gov/dao/prop2_filetest.gno +++ /dev/null @@ -1,120 +0,0 @@ -package main - -import ( - "std" - "time" - - "gno.land/p/demo/context" - "gno.land/p/gov/proposal" - gnoblog "gno.land/r/gnoland/blog" - govdao "gno.land/r/gov/dao" -) - -func init() { - membersFn := func() []std.Address { - return []std.Address{ - std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm"), - } - } - - mExec := govdao.NewPropExecutor(membersFn) - - comment := "adding someone to vote" - - id := govdao.Propose(comment, mExec) - - govdao.ExecuteProposal(id) - - executor := proposal.NewCtxExecutor(func(ctx context.Context) error { - gnoblog.DaoAddPost( - ctx, - "hello-from-govdao", // slug - "Hello from GovDAO!", // title - "This post was published by a GovDAO proposal.", // body - time.Now().Format(time.RFC3339), // publidation date - "moul", // authors - "govdao,example", // tags - ) - return nil - }) - - // Create a proposal. - // XXX: payment - comment = "post a new blogpost about govdao" - govdao.Propose(comment, executor) -} - -func main() { - println("--") - println(govdao.Render("")) - println("--") - println(govdao.Render("1")) - println("--") - govdao.VoteOnProposal(1, "YES") - println("--") - println(govdao.Render("1")) - println("--") - println(gnoblog.Render("")) - println("--") - govdao.ExecuteProposal(1) - println("--") - println(govdao.Render("1")) - println("--") - println(gnoblog.Render("")) -} - -// Output: -// -- -// - [0](/r/gov/dao:0) - adding someone to vote (**succeeded**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) -// - [1](/r/gov/dao:1) - post a new blogpost about govdao (**active**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) -// -// -- -// # Prop #1 -// -// post a new blogpost about govdao -// -// Status: active -// -// Voting status: YES: 0, NO: 0, percent: 0, members: 1 -// -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm -// -// -// -- -// -- -// # Prop #1 -// -// post a new blogpost about govdao -// -// Status: accepted -// -// Voting status: YES: 1, NO: 0, percent: 100, members: 1 -// -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm -// -// -// -- -// # Gnoland's Blog -// -// No posts. -// -- -// -- -// # Prop #1 -// -// post a new blogpost about govdao -// -// Status: succeeded -// -// Voting status: YES: 1, NO: 0, percent: 100, members: 1 -// -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm -// -// -// -- -// # Gnoland's Blog -// -//
-// -// ### [Hello from GovDAO!](/r/gnoland/blog:p/hello-from-govdao) -// 13 Feb 2009 -//
diff --git a/examples/gno.land/r/gov/dao/types.gno b/examples/gno.land/r/gov/dao/types.gno deleted file mode 100644 index 123fc489075..00000000000 --- a/examples/gno.land/r/gov/dao/types.gno +++ /dev/null @@ -1,32 +0,0 @@ -package govdao - -import ( - "std" -) - -// Status enum. -type Status string - -var ( - Accepted Status = "accepted" - Active Status = "active" - NotAccepted Status = "not accepted" - Expired Status = "expired" - Succeeded Status = "succeeded" -) - -// Voter defines the needed methods for a voting system -type Voter interface { - - // IsAccepted indicates if the voting process had been accepted - IsAccepted(voters []std.Address) bool - - // IsFinished indicates if the voting process is finished - IsFinished(voters []std.Address) bool - - // Vote adds a new vote to the voting system - Vote(voters []std.Address, caller std.Address, flag string) - - // Status returns a human friendly string describing how the voting process is going - Status(voters []std.Address) string -} diff --git a/examples/gno.land/r/gov/dao/v2/dao.gno b/examples/gno.land/r/gov/dao/v2/dao.gno new file mode 100644 index 00000000000..c37eda80bff --- /dev/null +++ b/examples/gno.land/r/gov/dao/v2/dao.gno @@ -0,0 +1,121 @@ +package govdao + +import ( + "std" + "strconv" + + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" + "gno.land/p/demo/simpledao" + "gno.land/p/demo/ufmt" +) + +var ( + d *simpledao.SimpleDAO // the current active DAO implementation + members membstore.MemberStore // the member store +) + +func init() { + var ( + // Example initial member set (just test addresses) + set = []membstore.Member{ + { + Address: std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm"), + VotingPower: 10, + }, + } + ) + + // Set the member store + members = membstore.NewMembStore(membstore.WithInitialMembers(set)) + + // Set the DAO implementation + d = simpledao.New(members) +} + +// Propose is designed to be called by another contract or with +// `maketx run`, not by a `maketx call`. +func Propose(request dao.ProposalRequest) uint64 { + idx, err := d.Propose(request) + if err != nil { + panic(err) + } + + return idx +} + +// VoteOnProposal casts a vote for the given proposal +func VoteOnProposal(id uint64, option dao.VoteOption) { + if err := d.VoteOnProposal(id, option); err != nil { + panic(err) + } +} + +// ExecuteProposal executes the proposal +func ExecuteProposal(id uint64) { + if err := d.ExecuteProposal(id); err != nil { + panic(err) + } +} + +// GetPropStore returns the active proposal store +func GetPropStore() dao.PropStore { + return d +} + +// GetMembStore returns the active member store +func GetMembStore() membstore.MemberStore { + return members +} + +func Render(path string) string { + if path == "" { + numProposals := d.Size() + + if numProposals == 0 { + return "No proposals found :(" // corner case + } + + output := "" + + offset := uint64(0) + if numProposals >= 10 { + offset = uint64(numProposals) - 10 + } + + // Fetch the last 10 proposals + for idx, prop := range d.Proposals(offset, uint64(10)) { + output += ufmt.Sprintf( + "- [Proposal #%d](%s:%d) - (**%s**)(by %s)\n", + idx, + "/r/gov/dao/v2", + idx, + prop.Status().String(), + prop.Author().String(), + ) + } + + return output + } + + // Display the detailed proposal + idx, err := strconv.Atoi(path) + if err != nil { + return "404: Invalid proposal ID" + } + + // Fetch the proposal + prop, err := d.ProposalByID(uint64(idx)) + if err != nil { + return ufmt.Sprintf("unable to fetch proposal, %s", err.Error()) + } + + // Render the proposal + output := "" + output += ufmt.Sprintf("# Prop #%d", idx) + output += "\n\n" + output += prop.Render() + output += "\n\n" + + return output +} diff --git a/examples/gno.land/r/gov/dao/v2/gno.mod b/examples/gno.land/r/gov/dao/v2/gno.mod new file mode 100644 index 00000000000..bc379bf18df --- /dev/null +++ b/examples/gno.land/r/gov/dao/v2/gno.mod @@ -0,0 +1,10 @@ +module gno.land/r/gov/dao/v2 + +require ( + gno.land/p/demo/combinederr v0.0.0-latest + gno.land/p/demo/dao v0.0.0-latest + gno.land/p/demo/membstore v0.0.0-latest + gno.land/p/demo/simpledao v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/gov/executor v0.0.0-latest +) diff --git a/examples/gno.land/r/gov/dao/v2/poc.gno b/examples/gno.land/r/gov/dao/v2/poc.gno new file mode 100644 index 00000000000..30d8a403f6e --- /dev/null +++ b/examples/gno.land/r/gov/dao/v2/poc.gno @@ -0,0 +1,92 @@ +package govdao + +import ( + "errors" + "std" + + "gno.land/p/demo/combinederr" + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" + "gno.land/p/gov/executor" +) + +var errNoChangesProposed = errors.New("no set changes proposed") + +// NewGovDAOExecutor creates the govdao wrapped callback executor +func NewGovDAOExecutor(cb func() error) dao.Executor { + if cb == nil { + panic(errNoChangesProposed) + } + + return executor.NewCallbackExecutor( + cb, + std.CurrentRealm().PkgPath(), + ) +} + +// NewMemberPropExecutor returns the GOVDAO member change executor +func NewMemberPropExecutor(changesFn func() []membstore.Member) dao.Executor { + if changesFn == nil { + panic(errNoChangesProposed) + } + + callback := func() error { + errs := &combinederr.CombinedError{} + cbMembers := changesFn() + + for _, member := range cbMembers { + switch { + case !members.IsMember(member.Address): + // Addition request + err := members.AddMember(member) + + errs.Add(err) + case member.VotingPower == 0: + // Remove request + err := members.UpdateMember(member.Address, membstore.Member{ + Address: member.Address, + VotingPower: 0, // 0 indicated removal + }) + + errs.Add(err) + default: + // Update request + err := members.UpdateMember(member.Address, member) + + errs.Add(err) + } + } + + // Check if there were any execution errors + if errs.Size() == 0 { + return nil + } + + return errs + } + + return NewGovDAOExecutor(callback) +} + +func NewMembStoreImplExecutor(changeFn func() membstore.MemberStore) dao.Executor { + if changeFn == nil { + panic(errNoChangesProposed) + } + + callback := func() error { + setMembStoreImpl(changeFn()) + + return nil + } + + return NewGovDAOExecutor(callback) +} + +// setMembStoreImpl sets a new dao.MembStore implementation +func setMembStoreImpl(impl membstore.MemberStore) { + if impl == nil { + panic("invalid member store") + } + + members = impl +} diff --git a/examples/gno.land/r/gov/dao/prop1_filetest.gno b/examples/gno.land/r/gov/dao/v2/prop1_filetest.gno similarity index 63% rename from examples/gno.land/r/gov/dao/prop1_filetest.gno rename to examples/gno.land/r/gov/dao/v2/prop1_filetest.gno index 49a200fd561..69e55ef1ab6 100644 --- a/examples/gno.land/r/gov/dao/prop1_filetest.gno +++ b/examples/gno.land/r/gov/dao/v2/prop1_filetest.gno @@ -10,26 +10,13 @@ package main import ( "std" + "gno.land/p/demo/dao" pVals "gno.land/p/sys/validators" - govdao "gno.land/r/gov/dao" - "gno.land/r/sys/validators" + govdao "gno.land/r/gov/dao/v2" + validators "gno.land/r/sys/validators/v2" ) -const daoPkgPath = "gno.land/r/gov/dao" - func init() { - membersFn := func() []std.Address { - return []std.Address{ - std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm"), - } - } - - mExec := govdao.NewPropExecutor(membersFn) - - comment := "adding someone to vote" - id := govdao.Propose(comment, mExec) - govdao.ExecuteProposal(id) - changesFn := func() []pVals.Validator { return []pVals.Validator{ { @@ -54,74 +41,84 @@ func init() { // complete governance proposal process. executor := validators.NewPropExecutor(changesFn) - // Create a proposal. - // XXX: payment - comment = "manual valset changes proposal example" - govdao.Propose(comment, executor) + // Create a proposal + description := "manual valset changes proposal example" + + prop := dao.ProposalRequest{ + Description: description, + Executor: executor, + } + + govdao.Propose(prop) } func main() { println("--") println(govdao.Render("")) println("--") - println(govdao.Render("1")) + println(govdao.Render("0")) println("--") - govdao.VoteOnProposal(1, "YES") + govdao.VoteOnProposal(0, dao.YesVote) println("--") - println(govdao.Render("1")) + println(govdao.Render("0")) println("--") println(validators.Render("")) println("--") - govdao.ExecuteProposal(1) + govdao.ExecuteProposal(0) println("--") - println(govdao.Render("1")) + println(govdao.Render("0")) println("--") println(validators.Render("")) } // Output: // -- -// - [0](/r/gov/dao:0) - adding someone to vote (**succeeded**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) -// - [1](/r/gov/dao:1) - manual valset changes proposal example (**active**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// - [Proposal #0](/r/gov/dao/v2:0) - (**active**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) // // -- -// # Prop #1 +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm // // manual valset changes proposal example // // Status: active // -// Voting status: YES: 0, NO: 0, percent: 0, members: 1 +// Voting stats: YAY 0 (0%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 10 (100%) // -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Threshold met: false // // // -- // -- -// # Prop #1 +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm // // manual valset changes proposal example // // Status: accepted // -// Voting status: YES: 1, NO: 0, percent: 100, members: 1 +// Voting stats: YAY 10 (100%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 0 (0%) // -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Threshold met: true // // // -- // No valset changes to apply. // -- // -- -// # Prop #1 +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm // // manual valset changes proposal example // -// Status: succeeded +// Status: execution successful // -// Voting status: YES: 1, NO: 0, percent: 100, members: 1 +// Voting stats: YAY 10 (100%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 0 (0%) // -// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Threshold met: true // // // -- diff --git a/examples/gno.land/r/gov/dao/v2/prop2_filetest.gno b/examples/gno.land/r/gov/dao/v2/prop2_filetest.gno new file mode 100644 index 00000000000..32ddc11b67c --- /dev/null +++ b/examples/gno.land/r/gov/dao/v2/prop2_filetest.gno @@ -0,0 +1,110 @@ +package main + +import ( + "time" + + "gno.land/p/demo/dao" + gnoblog "gno.land/r/gnoland/blog" + govdao "gno.land/r/gov/dao/v2" +) + +func init() { + ex := gnoblog.NewPostExecutor( + "hello-from-govdao", // slug + "Hello from GovDAO!", // title + "This post was published by a GovDAO proposal.", // body + time.Now().Format(time.RFC3339), // publication date + "moul", // authors + "govdao,example", // tags + ) + + // Create a proposal + description := "post a new blogpost about govdao" + + prop := dao.ProposalRequest{ + Description: description, + Executor: ex, + } + + govdao.Propose(prop) +} + +func main() { + println("--") + println(govdao.Render("")) + println("--") + println(govdao.Render("0")) + println("--") + govdao.VoteOnProposal(0, "YES") + println("--") + println(govdao.Render("0")) + println("--") + println(gnoblog.Render("")) + println("--") + govdao.ExecuteProposal(0) + println("--") + println(govdao.Render("0")) + println("--") + println(gnoblog.Render("")) +} + +// Output: +// -- +// - [Proposal #0](/r/gov/dao/v2:0) - (**active**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// +// -- +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// post a new blogpost about govdao +// +// Status: active +// +// Voting stats: YAY 0 (0%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 10 (100%) +// +// Threshold met: false +// +// +// -- +// -- +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// post a new blogpost about govdao +// +// Status: accepted +// +// Voting stats: YAY 10 (100%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 0 (0%) +// +// Threshold met: true +// +// +// -- +// # Gnoland's Blog +// +// No posts. +// -- +// -- +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// post a new blogpost about govdao +// +// Status: execution successful +// +// Voting stats: YAY 10 (100%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 0 (0%) +// +// Threshold met: true +// +// +// -- +// # Gnoland's Blog +// +//
+// +// ### [Hello from GovDAO!](/r/gnoland/blog:p/hello-from-govdao) +// 13 Feb 2009 +//
diff --git a/examples/gno.land/r/gov/dao/v2/prop3_filetest.gno b/examples/gno.land/r/gov/dao/v2/prop3_filetest.gno new file mode 100644 index 00000000000..5aa9947c74b --- /dev/null +++ b/examples/gno.land/r/gov/dao/v2/prop3_filetest.gno @@ -0,0 +1,120 @@ +package main + +import ( + "std" + + "gno.land/p/demo/dao" + "gno.land/p/demo/membstore" + govdao "gno.land/r/gov/dao/v2" +) + +func init() { + memberFn := func() []membstore.Member { + return []membstore.Member{ + { + Address: std.Address("g123"), + VotingPower: 10, + }, + { + Address: std.Address("g456"), + VotingPower: 10, + }, + { + Address: std.Address("g789"), + VotingPower: 10, + }, + } + } + + // Create a proposal + description := "add new members to the govdao" + + prop := dao.ProposalRequest{ + Description: description, + Executor: govdao.NewMemberPropExecutor(memberFn), + } + + govdao.Propose(prop) +} + +func main() { + println("--") + println(govdao.GetMembStore().Size()) + println("--") + println(govdao.Render("")) + println("--") + println(govdao.Render("0")) + println("--") + govdao.VoteOnProposal(0, "YES") + println("--") + println(govdao.Render("0")) + println("--") + println(govdao.Render("")) + println("--") + govdao.ExecuteProposal(0) + println("--") + println(govdao.Render("0")) + println("--") + println(govdao.Render("")) + println("--") + println(govdao.GetMembStore().Size()) +} + +// Output: +// -- +// 1 +// -- +// - [Proposal #0](/r/gov/dao/v2:0) - (**active**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// +// -- +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// add new members to the govdao +// +// Status: active +// +// Voting stats: YAY 0 (0%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 10 (100%) +// +// Threshold met: false +// +// +// -- +// -- +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// add new members to the govdao +// +// Status: accepted +// +// Voting stats: YAY 10 (100%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 0 (0%) +// +// Threshold met: true +// +// +// -- +// - [Proposal #0](/r/gov/dao/v2:0) - (**accepted**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// +// -- +// -- +// # Prop #0 +// +// Author: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// add new members to the govdao +// +// Status: execution successful +// +// Voting stats: YAY 10 (25%), NAY 0 (0%), ABSTAIN 0 (0%), HAVEN'T VOTED 30 (75%) +// +// Threshold met: false +// +// +// -- +// - [Proposal #0](/r/gov/dao/v2:0) - (**execution successful**)(by g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) +// +// -- +// 4 diff --git a/examples/gno.land/r/gov/dao/voter.gno b/examples/gno.land/r/gov/dao/voter.gno deleted file mode 100644 index 99223210791..00000000000 --- a/examples/gno.land/r/gov/dao/voter.gno +++ /dev/null @@ -1,91 +0,0 @@ -package govdao - -import ( - "std" - - "gno.land/p/demo/ufmt" -) - -const ( - yay = "YES" - nay = "NO" - - msgNoMoreVotesAllowed = "no more votes allowed" - msgAlreadyVoted = "caller already voted" - msgWrongVotingValue = "voting values must be YES or NO" -) - -func NewPercentageVoter(percent int) *PercentageVoter { - if percent < 0 || percent > 100 { - panic("percent value must be between 0 and 100") - } - - return &PercentageVoter{ - percentage: percent, - } -} - -// PercentageVoter is a system based on the amount of received votes. -// When the specified treshold is reached, the voting process finishes. -type PercentageVoter struct { - percentage int - - voters []std.Address - yes int - no int -} - -func (pv *PercentageVoter) IsAccepted(voters []std.Address) bool { - if len(voters) == 0 { - return true // special case - } - - return pv.percent(voters) >= pv.percentage -} - -func (pv *PercentageVoter) IsFinished(voters []std.Address) bool { - return pv.yes+pv.no >= len(voters) -} - -func (pv *PercentageVoter) Status(voters []std.Address) string { - return ufmt.Sprintf("YES: %d, NO: %d, percent: %d, members: %d", pv.yes, pv.no, pv.percent(voters), len(voters)) -} - -func (pv *PercentageVoter) Vote(voters []std.Address, caller std.Address, flag string) { - if pv.IsFinished(voters) { - panic(msgNoMoreVotesAllowed) - } - - if pv.alreadyVoted(caller) { - panic(msgAlreadyVoted) - } - - switch flag { - case yay: - pv.yes++ - pv.voters = append(pv.voters, caller) - case nay: - pv.no++ - pv.voters = append(pv.voters, caller) - default: - panic(msgWrongVotingValue) - } -} - -func (pv *PercentageVoter) percent(voters []std.Address) int { - if len(voters) == 0 { - return 0 - } - - return int((float32(pv.yes) / float32(len(voters))) * 100) -} - -func (pv *PercentageVoter) alreadyVoted(addr std.Address) bool { - for _, v := range pv.voters { - if v == addr { - return true - } - } - - return false -} diff --git a/examples/gno.land/r/sys/validators/doc.gno b/examples/gno.land/r/sys/validators/v2/doc.gno similarity index 100% rename from examples/gno.land/r/sys/validators/doc.gno rename to examples/gno.land/r/sys/validators/v2/doc.gno diff --git a/examples/gno.land/r/sys/validators/gno.mod b/examples/gno.land/r/sys/validators/v2/gno.mod similarity index 71% rename from examples/gno.land/r/sys/validators/gno.mod rename to examples/gno.land/r/sys/validators/v2/gno.mod index d9d129dd543..db94a208902 100644 --- a/examples/gno.land/r/sys/validators/gno.mod +++ b/examples/gno.land/r/sys/validators/v2/gno.mod @@ -1,12 +1,13 @@ -module gno.land/r/sys/validators +module gno.land/r/sys/validators/v2 require ( gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/dao v0.0.0-latest gno.land/p/demo/seqid 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 - gno.land/p/gov/proposal v0.0.0-latest gno.land/p/nt/poa v0.0.0-latest gno.land/p/sys/validators v0.0.0-latest + gno.land/r/gov/dao/bridge v0.0.0-latest ) diff --git a/examples/gno.land/r/sys/validators/gnosdk.gno b/examples/gno.land/r/sys/validators/v2/gnosdk.gno similarity index 100% rename from examples/gno.land/r/sys/validators/gnosdk.gno rename to examples/gno.land/r/sys/validators/v2/gnosdk.gno diff --git a/examples/gno.land/r/sys/validators/init.gno b/examples/gno.land/r/sys/validators/v2/init.gno similarity index 100% rename from examples/gno.land/r/sys/validators/init.gno rename to examples/gno.land/r/sys/validators/v2/init.gno diff --git a/examples/gno.land/r/sys/validators/poc.gno b/examples/gno.land/r/sys/validators/v2/poc.gno similarity index 63% rename from examples/gno.land/r/sys/validators/poc.gno rename to examples/gno.land/r/sys/validators/v2/poc.gno index e088b3b4293..760edc39d1e 100644 --- a/examples/gno.land/r/sys/validators/poc.gno +++ b/examples/gno.land/r/sys/validators/v2/poc.gno @@ -3,16 +3,12 @@ package validators import ( "std" - "gno.land/p/gov/proposal" + "gno.land/p/demo/dao" "gno.land/p/sys/validators" + "gno.land/r/gov/dao/bridge" ) -const daoPkgPath = "gno.land/r/gov/dao" - -const ( - errNoChangesProposed = "no set changes proposed" - errNotGovDAO = "caller not govdao executor" -) +const errNoChangesProposed = "no set changes proposed" // NewPropExecutor creates a new executor that wraps a changes closure // proposal. This wrapper is required to ensure the GovDAO Realm actually @@ -20,15 +16,12 @@ const ( // // Concept adapted from: // https://github.com/gnolang/gno/pull/1945 -func NewPropExecutor(changesFn func() []validators.Validator) proposal.Executor { +func NewPropExecutor(changesFn func() []validators.Validator) dao.Executor { if changesFn == nil { panic(errNoChangesProposed) } callback := func() error { - // Make sure the GovDAO executor runs the valset changes - assertGovDAOCaller() - for _, change := range changesFn() { if change.VotingPower == 0 { // This change request is to remove the validator @@ -44,14 +37,7 @@ func NewPropExecutor(changesFn func() []validators.Validator) proposal.Executor return nil } - return proposal.NewExecutor(callback) -} - -// assertGovDAOCaller verifies the caller is the GovDAO executor -func assertGovDAOCaller() { - if std.PrevRealm().PkgPath() != daoPkgPath { - panic(errNotGovDAO) - } + return bridge.GovDAO().NewGovDAOExecutor(callback) } // IsValidator returns a flag indicating if the given bech32 address diff --git a/examples/gno.land/r/sys/validators/validators.gno b/examples/gno.land/r/sys/validators/v2/validators.gno similarity index 100% rename from examples/gno.land/r/sys/validators/validators.gno rename to examples/gno.land/r/sys/validators/v2/validators.gno diff --git a/examples/gno.land/r/sys/validators/validators_test.gno b/examples/gno.land/r/sys/validators/v2/validators_test.gno similarity index 100% rename from examples/gno.land/r/sys/validators/validators_test.gno rename to examples/gno.land/r/sys/validators/v2/validators_test.gno diff --git a/gno.land/pkg/gnoland/validators.go b/gno.land/pkg/gnoland/validators.go index 1843dff3984..339ebd9dcad 100644 --- a/gno.land/pkg/gnoland/validators.go +++ b/gno.land/pkg/gnoland/validators.go @@ -9,7 +9,7 @@ import ( ) const ( - valRealm = "gno.land/r/sys/validators" + valRealm = "gno.land/r/sys/validators/v2" // XXX: make it configurable from GovDAO valChangesFn = "GetChanges" validatorAddedEvent = "ValidatorAdded" From ed919917ed1c802448487b8b4a3602db573606aa Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 29 Oct 2024 21:34:09 +0100 Subject: [PATCH 57/64] chore: remove install.gnogenesis from root makefile (#3045) Follow-up to #3041. Not even `gnoland` is part of the core commands in the root makefile, hence it makes no sense for `gnogenesis` to be one of them. --- Makefile | 6 +----- contribs/gnogenesis/README.md | 4 ++-- .../gno-infrastructure/validators/setting-up-a-new-chain.md | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 5cf8c8c58f9..2bfbe4e05e2 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ VERIFY_MOD_SUMS ?= false ######################################## # Dev tools .PHONY: install -install: install.gnokey install.gno install.gnodev install.gnogenesis +install: install.gnokey install.gno install.gnodev # shortcuts to frequently used commands from sub-components. .PHONY: install.gnokey @@ -45,10 +45,6 @@ install.gno: install.gnodev: $(MAKE) --no-print-directory -C ./contribs/gnodev install @printf "\033[0;32m[+] 'gnodev' has been installed. Read more in ./contribs/gnodev/\033[0m\n" -.PHONY: install.gnogenesis -install.gnogenesis: - $(MAKE) --no-print-directory -C ./contribs/gnogenesis install - @printf "\033[0;32m[+] 'gnogenesis' has been installed. Read more in ./contribs/gnogenesis/\033[0m\n" # old aliases diff --git a/contribs/gnogenesis/README.md b/contribs/gnogenesis/README.md index ae8daa6b81c..32cf3e6bb94 100644 --- a/contribs/gnogenesis/README.md +++ b/contribs/gnogenesis/README.md @@ -12,8 +12,8 @@ To install gnogenesis, clone the repository and build the tool: ```shell git clone https://github.com/gnoland/gno.git -cd gno -make install.gnogenesis +cd gno/contribs/gnogenesis +make install ``` This will compile and install `gnogenesis` to your system path, allowing you to run commands directly. 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 aab76eefbaf..5db8a7f1a59 100644 --- a/docs/gno-infrastructure/validators/setting-up-a-new-chain.md +++ b/docs/gno-infrastructure/validators/setting-up-a-new-chain.md @@ -30,7 +30,7 @@ Makefile to install the `gnoland` binary: ```bash cd gno.land -make install.gnoland install.gnogenesis +make install.gnoland && make -C contribs/gnogenesis install ``` To verify that you've installed the binary properly and that you are able to use From 9786fa366f922f04e1251ec6f1df6423b4fd2bf4 Mon Sep 17 00:00:00 2001 From: Morgan Date: Wed, 30 Oct 2024 15:12:24 +0100 Subject: [PATCH 58/64] chore: put replaces on gnolang/gno for all go.mods (#3046) Everything on this repository should default to always being on the latest master branch.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [x] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- .dockerignore | 4 +- .github/workflows/autocounterd.yml | 4 +- .github/workflows/portal-loop.yml | 1 - Dockerfile | 26 +- Dockerfile.release | 3 + contribs/gnodev/go.mod | 2 +- contribs/gnodev/go.sum | 4 +- contribs/gnofaucet/go.mod | 50 +- contribs/gnofaucet/go.sum | 109 +++-- contribs/gnogenesis/go.mod | 2 +- contribs/gnogenesis/go.sum | 4 +- contribs/gnokeykc/go.mod | 2 +- contribs/gnokeykc/go.sum | 4 +- go.mod | 4 +- go.sum | 4 +- misc/autocounterd/Dockerfile | 16 - misc/autocounterd/cmd/cmd_start.go | 24 +- misc/autocounterd/docker-compose.yml | 3 +- misc/autocounterd/go.mod | 77 +-- misc/autocounterd/go.sum | 284 ++++------- misc/devdeps/go.mod | 2 +- misc/devdeps/go.sum | 4 +- misc/docs-linter/go.mod | 10 +- misc/docs-linter/go.sum | 14 +- misc/loop/Dockerfile | 19 - misc/loop/docker-compose.yml | 2 +- misc/loop/go.mod | 57 ++- misc/loop/go.sum | 113 ++--- .../amino/tests/proto3/proto3_compat_test.go | 458 ------------------ 29 files changed, 391 insertions(+), 915 deletions(-) delete mode 100644 misc/autocounterd/Dockerfile delete mode 100644 misc/loop/Dockerfile delete mode 100644 tm2/pkg/amino/tests/proto3/proto3_compat_test.go diff --git a/.dockerignore b/.dockerignore index a45b7bafa98..3536640b4d7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,9 @@ .dockerignore build/ Dockerfile -misc/ +misc/* +!misc/loop/ +!misc/autocounterd/ docker-compose.yml tests/docker-integration/ diff --git a/.github/workflows/autocounterd.yml b/.github/workflows/autocounterd.yml index 66aced0d89c..63799960df5 100644 --- a/.github/workflows/autocounterd.yml +++ b/.github/workflows/autocounterd.yml @@ -1,6 +1,9 @@ name: autocounterd on: + pull_request: + branches: + - master push: paths: - misc/autocounterd @@ -41,7 +44,6 @@ jobs: - name: Build and push uses: docker/build-push-action@v6 with: - context: ./misc/autocounterd push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/portal-loop.yml b/.github/workflows/portal-loop.yml index b81957b22db..01135b164ac 100644 --- a/.github/workflows/portal-loop.yml +++ b/.github/workflows/portal-loop.yml @@ -45,7 +45,6 @@ jobs: - name: Build and push uses: docker/build-push-action@v6 with: - context: ./misc/loop target: portalloopd push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} diff --git a/Dockerfile b/Dockerfile index fa5a9e47270..b858589640f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,11 +10,20 @@ RUN --mount=type=cache,target=/root/.cache/go-build go build -o ./ 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 +# build misc binaries +FROM golang:1.22-alpine AS build-misc +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 build -C ./misc/loop -o /gnoroot/build/portalloopd ./cmd +RUN --mount=type=cache,target=/root/.cache/go-build go build -C ./misc/autocounterd -o /gnoroot/build/autocounterd ./cmd + # Base image FROM alpine:3.17 AS base WORKDIR /gnoroot ENV GNOROOT="/gnoroot" -RUN apk add ca-certificates +RUN apk add --no-cache ca-certificates CMD [ "" ] # alpine images @@ -47,6 +56,21 @@ COPY --from=build-gno /opt/gno/src/gno.land/cmd/gnoweb /opt/gno/src/gnowe EXPOSE 8888 ENTRYPOINT ["/usr/bin/gnoweb"] +# misc/loop +FROM docker AS portalloopd +WORKDIR /gnoroot +ENV GNOROOT="/gnoroot" +RUN apk add --no-cache ca-certificates bash curl jq +COPY --from=build-misc /gnoroot/build/portalloopd /usr/bin/portalloopd +ENTRYPOINT ["/usr/bin/portalloopd"] +CMD ["serve"] + +# misc/autocounterd +FROM base AS autocounterd +COPY --from=build-misc /gnoroot/build/autocounterd /usr/bin/autocounterd +ENTRYPOINT ["/usr/bin/autocounterd"] +CMD ["start"] + # all, contains everything. FROM base AS all COPY --from=build-gno /gnoroot/build/* /usr/bin/ diff --git a/Dockerfile.release b/Dockerfile.release index 4887857b5c2..481100c85c3 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -1,3 +1,6 @@ +# This file is similar to Dockerfile, but assumes that the binaries have +# already been created, and as such doesn't `go build` them. + FROM alpine AS base ENV GNOROOT="/gnoroot/" diff --git a/contribs/gnodev/go.mod b/contribs/gnodev/go.mod index c419f968d4a..a315d88591c 100644 --- a/contribs/gnodev/go.mod +++ b/contribs/gnodev/go.mod @@ -107,6 +107,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnodev/go.sum b/contribs/gnodev/go.sum index af57f320257..e38c3621483 100644 --- a/contribs/gnodev/go.sum +++ b/contribs/gnodev/go.sum @@ -326,8 +326,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/gnofaucet/go.mod b/contribs/gnofaucet/go.mod index c56c0b7d425..c5bb1ad0d81 100644 --- a/contribs/gnofaucet/go.mod +++ b/contribs/gnofaucet/go.mod @@ -6,15 +6,17 @@ toolchain go1.22.4 require ( github.com/gnolang/faucet v0.3.2 - github.com/gnolang/gno v0.1.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 ) +replace github.com/gnolang/gno => ../.. + require ( - github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect - github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect @@ -23,34 +25,34 @@ require ( github.com/go-logr/logr v1.4.2 // 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/gorilla/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/peterbourgon/ff/v3 v3.4.0 // indirect 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 + github.com/rs/cors v1.11.1 // indirect + github.com/rs/xid v1.6.0 // 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/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.25.0 // indirect + golang.org/x/crypto v0.26.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/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 + golang.org/x/mod v0.20.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.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 google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnofaucet/go.sum b/contribs/gnofaucet/go.sum index 1508cdae1e6..f4bdc65d7ec 100644 --- a/contribs/gnofaucet/go.sum +++ b/contribs/gnofaucet/go.sum @@ -1,18 +1,20 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/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.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= -github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +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= @@ -47,8 +49,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo 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/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= @@ -77,10 +77,10 @@ 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/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= -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/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/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= @@ -109,32 +109,37 @@ 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/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/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/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= -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.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.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= @@ -148,22 +153,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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +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/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/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 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= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.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= @@ -173,24 +178,24 @@ 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.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/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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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/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/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= @@ -199,8 +204,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/gnogenesis/go.mod b/contribs/gnogenesis/go.mod index cdd8922fad5..393fed0725d 100644 --- a/contribs/gnogenesis/go.mod +++ b/contribs/gnogenesis/go.mod @@ -57,6 +57,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnogenesis/go.sum b/contribs/gnogenesis/go.sum index 28c509e381e..f3161e47bad 100644 --- a/contribs/gnogenesis/go.sum +++ b/contribs/gnogenesis/go.sum @@ -212,8 +212,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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..0c794afd54c 100644 --- a/contribs/gnokeykc/go.mod +++ b/contribs/gnokeykc/go.mod @@ -59,6 +59,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/contribs/gnokeykc/go.sum b/contribs/gnokeykc/go.sum index b3bfadb3468..50eb5add218 100644 --- a/contribs/gnokeykc/go.sum +++ b/contribs/gnokeykc/go.sum @@ -216,8 +216,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/go.mod b/go.mod index 33f3a0f5212..24d09a87236 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/fortytw2/leaktest v1.3.0 github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 - github.com/golang/protobuf v1.5.4 github.com/google/gofuzz v1.2.0 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 @@ -45,7 +44,7 @@ require ( golang.org/x/sync v0.8.0 golang.org/x/term v0.23.0 golang.org/x/tools v0.24.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.35.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -53,6 +52,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + 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/securecookie v1.1.1 // indirect diff --git a/go.sum b/go.sum index 55b5681e559..78d60eeea90 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/misc/autocounterd/Dockerfile b/misc/autocounterd/Dockerfile deleted file mode 100644 index d860fc5f37f..00000000000 --- a/misc/autocounterd/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM golang:alpine AS builder - -COPY . /go/src/github.com/gnolang/gno/misc/autocounterd - -WORKDIR /go/src/github.com/gnolang/gno/misc/autocounterd - -RUN go build -o /build/autocounterd ./cmd - -# Final image for autocounterd -FROM alpine AS autocounterd - -COPY --from=builder /build/autocounterd /usr/bin/autocounterd - -ENTRYPOINT [ "/usr/bin/autocounterd" ] -CMD [ "start" ] - diff --git a/misc/autocounterd/cmd/cmd_start.go b/misc/autocounterd/cmd/cmd_start.go index a32d01fa324..ecf70f750be 100644 --- a/misc/autocounterd/cmd/cmd_start.go +++ b/misc/autocounterd/cmd/cmd_start.go @@ -7,6 +7,7 @@ import ( "time" "github.com/gnolang/gno/gno.land/pkg/gnoclient" + "github.com/gnolang/gno/gno.land/pkg/sdk/vm" rpcclient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" "github.com/gnolang/gno/tm2/pkg/commands" ) @@ -73,7 +74,10 @@ func execStart(cfg *startCfg, args []string, io commands.IO) error { return err } - rpcClient := rpcclient.NewHTTP(cfg.rpcURL, "/websocket") + rpcClient, err := rpcclient.NewHTTPClient(cfg.rpcURL) + if err != nil { + return err + } client := gnoclient.Client{ Signer: signer, @@ -81,14 +85,16 @@ func execStart(cfg *startCfg, args []string, io commands.IO) error { } for { - res, err := client.Call(gnoclient.CallCfg{ - PkgPath: cfg.realmPath, - FuncName: "Incr", - GasFee: "10000000ugnot", - GasWanted: 800000, - Args: nil, - }) - _ = res + _, err := client.Call( + gnoclient.BaseTxCfg{ + GasFee: "10000000ugnot", + GasWanted: 800000, + }, + vm.MsgCall{ + PkgPath: cfg.realmPath, + Func: "Incr", + Args: nil, + }) if err != nil { fmt.Printf("[ERROR] Failed to call Incr on %s, %+v\n", cfg.realmPath, err.Error()) diff --git a/misc/autocounterd/docker-compose.yml b/misc/autocounterd/docker-compose.yml index d71e6997b51..49d1ad413f3 100644 --- a/misc/autocounterd/docker-compose.yml +++ b/misc/autocounterd/docker-compose.yml @@ -3,7 +3,8 @@ services: autocounterd: image: ghcr.io/gnolang/gno/autocounterd build: - context: . + context: ../.. + target: autocounterd restart: unless-stopped environment: COUNTER_MNEMONIC: "source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast" diff --git a/misc/autocounterd/go.mod b/misc/autocounterd/go.mod index 12297e3c6ca..5de1d3c2974 100644 --- a/misc/autocounterd/go.mod +++ b/misc/autocounterd/go.mod @@ -1,54 +1,57 @@ -module loop +module autocounterd go 1.22 toolchain go1.22.4 -require github.com/gnolang/gno v0.0.0-20240125181217-b6193518e278 +require github.com/gnolang/gno v0.0.0-00010101000000-000000000000 require ( - dario.cat/mergo v1.0.0 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/btcutil v1.1.3 // indirect - github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // 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 github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/dgraph-io/badger/v3 v3.2103.5 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/gnolang/goleveldb v0.0.9 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect - github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/flatbuffers v1.12.1 // indirect - github.com/gorilla/websocket v1.5.1 // indirect - github.com/jaekwon/testify v1.6.1 // indirect - github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.12.3 // 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/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/linxGnu/grocksdb v1.8.11 // 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/cors v1.10.1 // indirect - github.com/stretchr/testify v1.8.4 // indirect - github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect - go.etcd.io/bbolt v1.3.8 // indirect - go.opencensus.io v0.22.5 // indirect - go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect - golang.org/x/tools v0.17.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + github.com/rs/xid v1.6.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/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/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 + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/gnolang/gno => ../.. diff --git a/misc/autocounterd/go.sum b/misc/autocounterd/go.sum index 905c884857e..b34cbde0c00 100644 --- a/misc/autocounterd/go.sum +++ b/misc/autocounterd/go.sum @@ -1,27 +1,24 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 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.0 h1:V2/ZgjfDFIygAX3ZapeigkVBoVUtOJKSwrhZdlpSvaA= -github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +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.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +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.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= -github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +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.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= @@ -31,17 +28,12 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +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/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= @@ -50,98 +42,59 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +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/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= -github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= -github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= -github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= 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= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gnolang/gno v0.0.0-20240125181217-b6193518e278 h1:CxF7gG3iqSeYVygTSYsB7Beg+Fpvka06TuTI2a0p+6s= -github.com/gnolang/gno v0.0.0-20240125181217-b6193518e278/go.mod h1:mOhpUTFaKk5CQj90qmjWfI9po2eapqziEu4D+fAtisc= -github.com/gnolang/goleveldb v0.0.9 h1:Q7rGko9oXMKtQA+Apeeed5a3sjba/mcDhzJGoTVLCKE= -github.com/gnolang/goleveldb v0.0.9/go.mod h1:Dz6p9bmpy/FBESTgduiThZt5mToVDipcHGzj/zUOo8E= 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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +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/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= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= -github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +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.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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jaekwon/testify v1.6.1 h1:4AtAJcR9GzXN5W4DdY7ie74iCPiJV1JJUJL90t2ZUyw= -github.com/jaekwon/testify v1.6.1/go.mod h1:Oun0RXIHI7osufabQ60i4Lqkj0GXLbqI1I7kgzBNm1U= 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= -github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= -github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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/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/linxGnu/grocksdb v1.8.11 h1:BGol9e5gB1BrsTvOxloC88pe70TCqgrfLNwkyWW0kD8= -github.com/linxGnu/grocksdb v1.8.11/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 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= @@ -155,7 +108,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= @@ -164,146 +116,113 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= -github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +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/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= -go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap/exp v0.1.0 h1:Ol9zQNvAEAgFHSBiR5LlwS9Xq8u5QF+7HBwNHUB8rcI= -go.uber.org/zap/exp v0.1.0/go.mod h1:z/0T3As39ttolxZGOsvk1OEvQfwwfTZpmV9YTp+VAkc= +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.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= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.2.0 h1:FtGenNNeCATRB3CmB/yEUnjEFeJWpB/pMcy7e2bKPYs= +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-20181203042331-505ab145d0a9/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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/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/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +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/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +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/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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +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/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= 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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -311,4 +230,3 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/misc/devdeps/go.mod b/misc/devdeps/go.mod index 2ca693afc93..c07b82fd11d 100644 --- a/misc/devdeps/go.mod +++ b/misc/devdeps/go.mod @@ -8,7 +8,7 @@ require ( github.com/golangci/golangci-lint v1.59.1 // sync with github action golang.org/x/tools v0.22.1-0.20240628205440-9c895dd76b34 golang.org/x/tools/gopls v0.16.1 - google.golang.org/protobuf v1.33.0 + google.golang.org/protobuf v1.35.1 moul.io/testman v1.5.0 mvdan.cc/gofumpt v0.6.0 ) diff --git a/misc/devdeps/go.sum b/misc/devdeps/go.sum index 4c3f84b6df7..e19e47d0c56 100644 --- a/misc/devdeps/go.sum +++ b/misc/devdeps/go.sum @@ -942,8 +942,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/misc/docs-linter/go.mod b/misc/docs-linter/go.mod index be771c9a952..e27b82ef2f5 100644 --- a/misc/docs-linter/go.mod +++ b/misc/docs-linter/go.mod @@ -5,17 +5,19 @@ go 1.22 toolchain go1.22.4 require ( - github.com/gnolang/gno v0.0.0-20240516161351-0c9849a8ef0c + github.com/gnolang/gno v0.0.0-00010101000000-000000000000 github.com/stretchr/testify v1.9.0 - golang.org/x/sync v0.7.0 + golang.org/x/sync v0.8.0 mvdan.cc/xurls/v2 v2.5.0 ) +replace github.com/gnolang/gno => ../.. + require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/peterbourgon/ff/v3 v3.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/term v0.23.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/misc/docs-linter/go.sum b/misc/docs-linter/go.sum index ab8c3cf7c48..4957bd0cc88 100644 --- a/misc/docs-linter/go.sum +++ b/misc/docs-linter/go.sum @@ -1,19 +1,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gnolang/gno v0.0.0-20240516161351-0c9849a8ef0c h1:jtZ+oN8ZpBM0wYbcFH0B7NjFFzTFqZZmZellSSKtaCE= -github.com/gnolang/gno v0.0.0-20240516161351-0c9849a8ef0c/go.mod h1:YcZbtNIfXVn4jS1pSG8SeG5RVHjyI7FPS3GypZaXxCI= github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= -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.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/misc/loop/Dockerfile b/misc/loop/Dockerfile deleted file mode 100644 index 219a47927db..00000000000 --- a/misc/loop/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM golang:alpine AS builder - -COPY . /go/src/github.com/gnolang/gno/misc/loop - -WORKDIR /go/src/github.com/gnolang/gno/misc/loop - -RUN --mount=type=cache,target=/root/.cache/go-build \ - --mount=type=cache,target=/root/go/pkg/mod \ - go build -o /build/portalloopd ./cmd - -# Final image for portalloopd -FROM docker AS portalloopd - -RUN apk add bash curl jq - -COPY --from=builder /build/portalloopd /usr/bin/portalloopd - -ENTRYPOINT [ "/usr/bin/portalloopd" ] -CMD [ "serve" ] diff --git a/misc/loop/docker-compose.yml b/misc/loop/docker-compose.yml index eba0f55e787..ed2fe7192f5 100644 --- a/misc/loop/docker-compose.yml +++ b/misc/loop/docker-compose.yml @@ -68,7 +68,7 @@ services: portalloopd: build: - context: . + context: ../.. target: portalloopd restart: unless-stopped volumes: diff --git a/misc/loop/go.mod b/misc/loop/go.mod index be37c21f5c9..2d749759bfb 100644 --- a/misc/loop/go.mod +++ b/misc/loop/go.mod @@ -7,22 +7,23 @@ toolchain go1.22.4 require ( github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 - github.com/gnolang/gno v0.1.0-nightly.20240707 + github.com/gnolang/gno v0.1.0-nightly.20240627 github.com/gnolang/tx-archive v0.3.0 github.com/prometheus/client_golang v1.17.0 github.com/sirupsen/logrus v1.9.3 ) +replace github.com/gnolang/gno => ../.. + require ( - dario.cat/mergo v1.0.0 // indirect + dario.cat/mergo v1.0.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect - github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect - github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/distribution/reference v0.5.0 // indirect @@ -35,8 +36,8 @@ 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/websocket v1.5.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/moby/term v0.5.0 // indirect @@ -50,37 +51,35 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect - github.com/rs/cors v1.11.0 // indirect - github.com/rs/xid v1.5.0 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/rs/xid v1.6.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.etcd.io/bbolt v1.3.9 // 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.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.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.2.0 // indirect - golang.org/x/crypto v0.25.0 // indirect + golang.org/x/crypto v0.26.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/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // 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 golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.22.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 + 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 google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/misc/loop/go.sum b/misc/loop/go.sum index 2ad488a5f25..c80bfb42c2f 100644 --- a/misc/loop/go.sum +++ b/misc/loop/go.sum @@ -1,5 +1,5 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -9,16 +9,18 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= -github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +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= @@ -66,8 +68,6 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gnolang/gno v0.1.0-nightly.20240707 h1:ez1BtiwRuqRHRxvqyKDbUbNtUBYEjXwSHqRu6m347os= -github.com/gnolang/gno v0.1.0-nightly.20240707/go.mod h1:BTaBNeaoY/W95NN6QA4RCoQ6Z7mi8M+Zb1I1wMWGg2w= 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/gnolang/tx-archive v0.3.0 h1:5Fr39yAT7nnAPKvcmKmBT+oPiBhMhA0aUAIEeXrYG4I= @@ -100,10 +100,10 @@ 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/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= -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/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/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= @@ -160,14 +160,19 @@ github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwa github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= 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.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/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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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= @@ -178,22 +183,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.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.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.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= @@ -208,14 +213,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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.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= @@ -224,15 +229,15 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL 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.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.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= @@ -244,32 +249,32 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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.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/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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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-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/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/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= @@ -278,8 +283,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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/tm2/pkg/amino/tests/proto3/proto3_compat_test.go b/tm2/pkg/amino/tests/proto3/proto3_compat_test.go deleted file mode 100644 index 8f9e04fc35c..00000000000 --- a/tm2/pkg/amino/tests/proto3/proto3_compat_test.go +++ /dev/null @@ -1,458 +0,0 @@ -//go:build extensive_tests - -// only built if manually enforced (via the build tag above) -package proto3 - -import ( - "bufio" - "bytes" - "encoding/binary" - "math" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" - - p3 "github.com/gnolang/gno/tm2/pkg/amino/tests/proto3/proto" - - "github.com/gnolang/gno/tm2/pkg/amino" - "github.com/gnolang/gno/tm2/pkg/amino/tests" -) - -// This file checks basic proto3 compatibility by checking encoding of some test-vectors generated by using protoc. - -var ( - cdc = amino.NewCodec() - epoch time.Time -) - -func init() { - cdc.Seal() - epoch, _ = time.Parse("2006-01-02 15:04:05 +0000 UTC", "1970-01-01 00:00:00 +0000 UTC") -} - -func TestFixed32Roundtrip(t *testing.T) { - t.Parallel() - - // amino fixed32 (int32) <-> protbuf fixed32 (uint32) - type testi32 struct { - Int32 int32 `binary:"fixed32"` - } - ab, err := cdc.Marshal(testi32{Int32: 150}) - assert.NoError(t, err, "unexpected error") - - pb, err := proto.Marshal(&p3.TestInt32Fixed{Fixed32: 150}) - assert.NoError(t, err, "unexpected error") - - assert.Equal(t, pb, ab, "fixed32 (int32) encoding doesn't match") - - // unmarshal (from amino to proto and vice versa) - var att testi32 - var pt p3.Test32 - err = proto.Unmarshal(ab, &pt) - assert.NoError(t, err, "unexpected error") - - err = cdc.Unmarshal(pb, &att) - assert.NoError(t, err, "unexpected error") - - assert.Equal(t, uint32(att.Int32), pt.Foo) -} - -func TestVarintZigzagRoundtrip(t *testing.T) { - t.Parallel() - - t.Skip("zigzag encoding isn't default anymore for (unsigned) ints") - // amino varint (int) <-> protobuf zigzag32 (int32 in go sint32 in proto file) - type testInt32Varint struct { - Int32 int `binary:"varint"` - } - varint := testInt32Varint{Int32: 6000000} - ab, err := cdc.Marshal(varint) - assert.NoError(t, err, "unexpected error") - pb, err := proto.Marshal(&p3.TestInt32Varint{Int32: 6000000}) - assert.NoError(t, err, "unexpected error") - assert.Equal(t, pb, ab, "varint encoding doesn't match") - - var amToP3 p3.TestInt32Varint - var p3ToAm testInt32Varint - err = proto.Unmarshal(ab, &amToP3) - assert.NoError(t, err, "unexpected error") - - err = cdc.Unmarshal(pb, &p3ToAm) - assert.NoError(t, err, "unexpected error") - - assert.EqualValues(t, varint.Int32, amToP3.Int32) -} - -func TestFixedU64Roundtrip(t *testing.T) { - t.Parallel() - - type testFixed64Uint struct { - Int64 uint64 `binary:"fixed64"` - } - - pvint64 := p3.TestFixedInt64{Int64: 150} - avint64 := testFixed64Uint{Int64: 150} - ab, err := cdc.Marshal(avint64) - assert.NoError(t, err, "unexpected error") - - pb, err := proto.Marshal(&pvint64) - assert.NoError(t, err, "unexpected error") - - assert.Equal(t, pb, ab, "fixed64 encoding doesn't match") - - var amToP3 p3.TestFixedInt64 - var p3ToAm testFixed64Uint - err = proto.Unmarshal(ab, &amToP3) - assert.NoError(t, err, "unexpected error") - - err = cdc.Unmarshal(pb, &p3ToAm) - assert.NoError(t, err, "unexpected error") - - assert.EqualValues(t, p3ToAm.Int64, amToP3.Int64) -} - -func TestMultidimensionalSlices(t *testing.T) { - t.Parallel() - - s := [][]int8{ - {1, 2}, - {3, 4, 5}, - } - - _, err := cdc.Marshal(s) - assert.Error(t, err, "expected error: multidimensional slices are not allowed") -} - -func TestMultidimensionalArrays(t *testing.T) { - t.Parallel() - - arr := [2][2]int8{ - {1, 2}, - {3, 4}, - } - - _, err := cdc.Marshal(arr) - assert.Error(t, err, "expected error: multidimensional arrays are not allowed") -} - -func TestMultidimensionalByteArraysAndSlices(t *testing.T) { - t.Parallel() - - arr := [2][2]byte{ - {1, 2}, - {3, 4}, - } - - _, err := cdc.Marshal(arr) - assert.NoError(t, err, "unexpected error: multidimensional arrays are allowed, as long as they are only of bytes") - - s := [][]byte{ - {1, 2}, - {3, 4, 5}, - } - - _, err = cdc.Marshal(s) - assert.NoError(t, err, "unexpected error: multidimensional slices are allowed, as long as they are only of bytes") - - s2 := [][][]byte{{ - {1, 2}, - {3, 4, 5}, - }} - - _, err = cdc.Marshal(s2) - assert.NoError(t, err, "unexpected error: multidimensional slices are allowed, as long as they are only of bytes") -} - -func TestProto3CompatPtrsRoundtrip(t *testing.T) { - t.Parallel() - - s := p3.SomeStruct{} - - ab, err := cdc.Marshal(s) - assert.NoError(t, err) - - pb, err := proto.Marshal(&s) - assert.NoError(t, err) - // This fails as amino currently returns []byte(nil) - // while protobuf returns []byte{}: - // - // assert.Equal(t, ab, pb) - // - // Semantically, that's no problem though. Hence, we only check for zero length: - assert.Zero(t, len(ab), "expected an empty encoding for a nil pointer") - t.Log(ab) - - var amToP3 p3.SomeStruct - var p3ToAm p3.SomeStruct - err = proto.Unmarshal(ab, &amToP3) - assert.NoError(t, err, "unexpected error") - - err = cdc.Unmarshal(pb, &p3ToAm) - assert.NoError(t, err, "unexpected error") - - assert.EqualValues(t, p3ToAm, amToP3) - - s2 := p3.SomeStruct{Emb: &p3.EmbeddedStruct{}} - - ab, err = cdc.Marshal(s2) - assert.NoError(t, err) - - pb, err = proto.Marshal(&s2) - assert.NoError(t, err) - assert.Equal(t, ab, pb) - - err = proto.Unmarshal(ab, &amToP3) - assert.NoError(t, err, "unexpected error") - - err = cdc.Unmarshal(pb, &p3ToAm) - assert.NoError(t, err, "unexpected error") - - assert.EqualValues(t, p3ToAm, amToP3) - - assert.NotZero(t, len(ab), "expected a non-empty encoding for a non-nil pointer to an empty struct") - t.Log(ab) -} - -// --------------------------------------------------------------- -// ---- time.Time <-> timestamp.Timestamp (proto3 well known type) : -// --------------------------------------------------------------- - -// equivalent go struct or "type" to the proto3 message: -type goAminoGotTime struct { - T *time.Time -} - -func TestProto3CompatEmptyTimestamp(t *testing.T) { - t.Parallel() - - empty := p3.ProtoGotTime{} - // protobuf also marshals to empty bytes here: - pb, err := proto.Marshal(&empty) - assert.NoError(t, err) - assert.Len(t, pb, 0) - - // unmarshaling an empty slice behaves a bit differently in proto3 compared to amino: - res := &goAminoGotTime{} - err = cdc.Unmarshal(pb, res) - assert.NoError(t, err) - // NOTE: this behaves differently because amino defaults the time to 1970-01-01 00:00:00 +0000 UTC while - // decoding; protobuf defaults to nil here (see the following lines below): - assert.NoError(t, err) - assert.Equal(t, goAminoGotTime{T: &epoch}, *res) - pbRes := p3.ProtoGotTime{} - err = proto.Unmarshal(pb, &pbRes) - assert.NoError(t, err) - assert.Equal(t, p3.ProtoGotTime{T: nil}, pbRes) -} - -func TestProto3CompatTimestampNow(t *testing.T) { - t.Parallel() - - // test with current time: - now := time.Now() - ptts, err := ptypes.TimestampProto(now) - assert.NoError(t, err) - pt := p3.ProtoGotTime{T: ptts} - at := goAminoGotTime{T: &now} - ab1, err := cdc.Marshal(at) - assert.NoError(t, err) - ab2, err := cdc.Marshal(pt) - assert.NoError(t, err) - // amino's encoding of time.Time is the same as proto's encoding of the well known type - // timestamp.Timestamp (they can be used interchangeably): - assert.Equal(t, ab1, ab2) - pb, err := proto.Marshal(&pt) - assert.NoError(t, err) - assert.Equal(t, ab1, pb) - - pbRes := p3.ProtoGotTime{} - err = proto.Unmarshal(ab1, &pbRes) - assert.NoError(t, err) - got, err := ptypes.Timestamp(pbRes.T) - assert.NoError(t, err) - _, err = ptypes.TimestampProto(now) - assert.NoError(t, err) - err = proto.Unmarshal(pb, &pbRes) - assert.NoError(t, err) - // create time.Time from timestamp.Timestamp and check if they are the same: - got, err = ptypes.Timestamp(pbRes.T) - assert.Equal(t, got.UTC(), now.UTC()) -} - -func TestProto3EpochTime(t *testing.T) { - t.Parallel() - - pbRes := p3.ProtoGotTime{} - // amino encode epoch (1970) and decode using proto; expect the resulting time to be epoch again: - ab, err := cdc.Marshal(goAminoGotTime{T: &epoch}) - assert.NoError(t, err) - err = proto.Unmarshal(ab, &pbRes) - assert.NoError(t, err) - ts, err := ptypes.Timestamp(pbRes.T) - assert.NoError(t, err) - assert.EqualValues(t, ts, epoch) -} - -func TestProtoNegativeSeconds(t *testing.T) { - t.Parallel() - - pbRes := p3.ProtoGotTime{} - // test with negative seconds (0001-01-01 -> seconds = -62135596800, nanos = 0): - ntm, err := time.Parse("2006-01-02 15:04:05 +0000 UTC", "0001-01-01 00:00:00 +0000 UTC") - ab, err := cdc.Marshal(goAminoGotTime{T: &ntm}) - assert.NoError(t, err) - res := &goAminoGotTime{} - err = cdc.Unmarshal(ab, res) - assert.NoError(t, err) - assert.EqualValues(t, ntm, *res.T) - err = proto.Unmarshal(ab, &pbRes) - assert.NoError(t, err) - got, err := ptypes.Timestamp(pbRes.T) - assert.NoError(t, err) - assert.Equal(t, got, ntm) -} - -func TestIntVarintCompat(t *testing.T) { - t.Parallel() - - tcs := []struct { - val32 int32 - val64 int64 - }{ - {1, 1}, - {-1, -1}, - {2, 2}, - {1000, 1000}, - {math.MaxInt32, math.MaxInt64}, - {math.MinInt32, math.MinInt64}, - } - for _, tc := range tcs { - tv := p3.TestInts{Int32: tc.val32, Int64: tc.val64} - ab, err := cdc.Marshal(tv) - assert.NoError(t, err) - pb, err := proto.Marshal(&tv) - assert.NoError(t, err) - assert.Equal(t, ab, pb) - var res p3.TestInts - err = cdc.Unmarshal(pb, &res) - assert.NoError(t, err) - var res2 p3.TestInts - err = proto.Unmarshal(ab, &res2) - assert.NoError(t, err) - assert.Equal(t, res.Int32, tc.val32) - assert.Equal(t, res.Int64, tc.val64) - assert.Equal(t, res2.Int32, tc.val32) - assert.Equal(t, res2.Int64, tc.val64) - } - // special case: amino allows int as well - // test that ints are also varint encoded: - type TestInt struct { - Int int - } - tcs2 := []struct { - val int - }{ - {0}, - {-1}, - {1000}, - {-1000}, - {math.MaxInt32}, - {math.MinInt32}, - } - for _, tc := range tcs2 { - ptv := p3.TestInts{Int32: int32(tc.val)} - pb, err := proto.Marshal(&ptv) - assert.NoError(t, err) - atv := TestInt{tc.val} - ab, err := cdc.Marshal(atv) - assert.NoError(t, err) - if tc.val == 0 { - // amino results in []byte(nil) - // protobuf in []byte{} - assert.Empty(t, ab) - assert.Empty(t, pb) - } else { - assert.Equal(t, ab, pb) - } - // can we get back the int from the proto? - var res TestInt - err = cdc.Unmarshal(pb, &res) - assert.NoError(t, err) - assert.EqualValues(t, res.Int, tc.val) - } - - // purposely overflow by writing a too large value to first field (which is int32): - fieldNum := 1 - fieldNumAndType := (uint64(fieldNum) << 3) | uint64(amino.Typ3Varint) - var b bytes.Buffer - writer := bufio.NewWriter(&b) - var buf [10]byte - n := binary.PutUvarint(buf[:], fieldNumAndType) - _, err := writer.Write(buf[0:n]) - assert.NoError(t, err) - amino.EncodeUvarint(writer, math.MaxInt32+1) - err = writer.Flush() - assert.NoError(t, err) - - var res p3.TestInts - err = cdc.Unmarshal(b.Bytes(), &res) - assert.Error(t, err) -} - -// See if encoding of type def types matches the proto3 encoding -func TestTypeDefCompatibility(t *testing.T) { - t.Parallel() - - pNow := ptypes.TimestampNow() - now, err := ptypes.Timestamp(pNow) - require.NoError(t, err) - - strSl := tests.PrimitivesStructSl{ - {Int32: 1, Int64: -1, Varint: 2, String: "protobuf3", Bytes: []byte("got some bytes"), Time: now}, - {Int32: 0, Int64: 1, Varint: -2, String: "amino", Bytes: []byte("more of these bytes"), Time: now}, - } - strAr := tests.PrimitivesStructAr{strSl[0], strSl[1]} - p3StrSl := &p3.PrimitivesStructSl{ - Structs: []*p3.PrimitivesStruct{ - {Int32: 1, Int64: -1, Varint: 2, String_: "protobuf3", Bytes: []byte("got some bytes"), Time: pNow}, - {Int32: 0, Int64: 1, Varint: -2, String_: "amino", Bytes: []byte("more of these bytes"), Time: pNow}, - }, - } - - tcs := []struct { - AminoType interface{} - ProtoMsg proto.Message - }{ - // type IntDef int - 0: {tests.IntDef(0), &p3.IntDef{}}, - 1: {tests.IntDef(0), &p3.IntDef{Val: 0}}, - 2: {tests.IntDef(1), &p3.IntDef{Val: 1}}, - 3: {tests.IntDef(-1), &p3.IntDef{Val: -1}}, - - // type IntAr [4]int - 4: {tests.IntAr{1, 2, 3, 4}, &p3.IntArr{Val: []int64{1, 2, 3, 4}}}, - 5: {tests.IntAr{0, -2, 3, 4}, &p3.IntArr{Val: []int64{0, -2, 3, 4}}}, - - // type IntSl []int (protobuf doesn't really have arrays) - 6: {tests.IntSl{1, 2, 3, 4}, &p3.IntArr{Val: []int64{1, 2, 3, 4}}}, - - // type PrimitivesStructSl []PrimitivesStruct - 7: {strSl, p3StrSl}, - // type PrimitivesStructAr [2]PrimitivesStruct - 8: {strAr, p3StrSl}, - } - for i, tc := range tcs { - ab, err := amino.Marshal(tc.AminoType) - require.NoError(t, err) - - pb, err := proto.Marshal(tc.ProtoMsg) - require.NoError(t, err) - - assert.Equal(t, pb, ab, "Amino and protobuf encoding do not match %v", i) - } -} From 850182caf3040ca06a590900918fed9c15eb9028 Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:15:34 +0100 Subject: [PATCH 59/64] fix(gnovm): forbid star expression when value is not a pointer (#2984) closes: #1088
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- gnovm/pkg/gnolang/preprocess.go | 7 ++++++- gnovm/tests/files/ptr9.gno | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 gnovm/tests/files/ptr9.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 2d65dfa5cb1..10c55979520 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1757,7 +1757,12 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { case *KeyValueExpr: // NOTE: For simplicity we just // use the *CompositeLitExpr. - + // TRANS_LEAVE ----------------------- + case *StarExpr: + xt := evalStaticTypeOf(store, last, n.X) + if xt.Kind() != PointerKind && xt.Kind() != TypeKind { + panic(fmt.Sprintf("invalid operation: cannot indirect %s (variable of type %s)", n.X.String(), xt.String())) + } // TRANS_LEAVE ----------------------- case *SelectorExpr: xt := evalStaticTypeOf(store, last, n.X) diff --git a/gnovm/tests/files/ptr9.gno b/gnovm/tests/files/ptr9.gno new file mode 100644 index 00000000000..6e104942d81 --- /dev/null +++ b/gnovm/tests/files/ptr9.gno @@ -0,0 +1,9 @@ +package main + +func main() { + v := 1 + println(*v) +} + +// Error: +// main/files/ptr9.gno:5:10: invalid operation: cannot indirect v (variable of type int) From 494976da31d8c4c9d00a5074e9254429463b6291 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Thu, 31 Oct 2024 05:46:10 +0900 Subject: [PATCH 60/64] feat(p/json): remove unnecessary code and optimize (#2939) # Description Optimized the JSON package and simplified JSON node creation using the builder pattern. - in `buffer.gno` and `escape.gno` files are modified the use of map for lookup tables to use slice array instead. - refactor the `Unquote` function in `escape.gno` file - modified the existing functions that parsed numbers to use `strconv` package, and deleted related files and functions - especially, the `eisel_lemire` and `ryu` packages were deleted since they were files that had been added to handle `ParseUint` and `ParseFloat` in `strconv` package. ## JSON Generate Example **Plain JSON** ```go node := Builder(). WithString("name", "Alice"). WithNumber("age", 30). WithBool("is_student", false). Node() value, err := Marshal(node) if err != nil { t.Errorf("unexpected error: %s", err) } Output: {"name":"Alice","age":30,"is_student":false} ``` **Nested Structure** ```go node := Builder(). WriteString("name", "Alice"). WriteObject("address", func(b *NodeBuilder) { b.WriteString("city", "New York"). WriteNumber("zipcode", 10001) }). Node() // ... Output: {"name":"Alice","address":{"city":"New York","zipcode":10001}} ``` ## Benchmark Result for Unquote **Before** ```plain BenchmarkUnquote-8 12433488 98.06 ns/op 144 B/op 2 allocs/op BenchmarkUnquoteWorstCase-8 24727736 50.46 ns/op 48 B/op 1 allocs/op BenchmarkUnquoteBestCase-8 22542354 52.69 ns/op 48 B/op 1 allocs/op BenchmarkUnquoteEmptyString-8 394868628 3.067 ns/op 0 B/op 0 allocs/op ``` **After** ```plain BenchmarkUnquote-8 12464704 96.61 ns/op 144 B/op 2 allocs/op BenchmarkUnquoteWorstCase-8 25084070 48.02 ns/op 48 B/op 1 allocs/op BenchmarkUnquoteBestCase-8 23383227 52.66 ns/op 48 B/op 1 allocs/op BenchmarkUnquoteEmptyString-8 400496838 2.968 ns/op 0 B/op 0 allocs/op ``` --- examples/gno.land/p/demo/json/buffer.gno | 65 +- examples/gno.land/p/demo/json/buffer_test.gno | 35 +- examples/gno.land/p/demo/json/builder.gno | 89 ++ .../gno.land/p/demo/json/builder_test.gno | 103 +++ examples/gno.land/p/demo/json/decode_test.gno | 2 +- .../p/demo/json/eisel_lemire/eisel_lemire.gno | 839 ------------------ .../gno.land/p/demo/json/eisel_lemire/gno.mod | 1 - examples/gno.land/p/demo/json/encode.gno | 15 +- examples/gno.land/p/demo/json/encode_test.gno | 5 +- examples/gno.land/p/demo/json/errors.gno | 34 + examples/gno.land/p/demo/json/escape.gno | 114 ++- examples/gno.land/p/demo/json/escape_test.gno | 61 +- examples/gno.land/p/demo/json/gno.mod | 6 +- examples/gno.land/p/demo/json/indent.gno | 16 +- examples/gno.land/p/demo/json/node.gno | 56 +- examples/gno.land/p/demo/json/parser.gno | 161 +--- examples/gno.land/p/demo/json/parser_test.gno | 122 --- examples/gno.land/p/demo/json/ryu/License | 21 - .../gno.land/p/demo/json/ryu/floatconv.gno | 143 --- .../p/demo/json/ryu/floatconv_test.gno | 33 - examples/gno.land/p/demo/json/ryu/gno.mod | 1 - examples/gno.land/p/demo/json/ryu/ryu64.gno | 344 ------- examples/gno.land/p/demo/json/ryu/table.gno | 678 -------------- 23 files changed, 383 insertions(+), 2561 deletions(-) create mode 100644 examples/gno.land/p/demo/json/builder.gno create mode 100644 examples/gno.land/p/demo/json/builder_test.gno delete mode 100644 examples/gno.land/p/demo/json/eisel_lemire/eisel_lemire.gno delete mode 100644 examples/gno.land/p/demo/json/eisel_lemire/gno.mod create mode 100644 examples/gno.land/p/demo/json/errors.gno delete mode 100644 examples/gno.land/p/demo/json/ryu/License delete mode 100644 examples/gno.land/p/demo/json/ryu/floatconv.gno delete mode 100644 examples/gno.land/p/demo/json/ryu/floatconv_test.gno delete mode 100644 examples/gno.land/p/demo/json/ryu/gno.mod delete mode 100644 examples/gno.land/p/demo/json/ryu/ryu64.gno delete mode 100644 examples/gno.land/p/demo/json/ryu/table.gno diff --git a/examples/gno.land/p/demo/json/buffer.gno b/examples/gno.land/p/demo/json/buffer.gno index 23fb53fb0ea..a217ee653f9 100644 --- a/examples/gno.land/p/demo/json/buffer.gno +++ b/examples/gno.land/p/demo/json/buffer.gno @@ -3,7 +3,6 @@ package json import ( "errors" "io" - "strings" "gno.land/p/demo/ufmt" ) @@ -112,28 +111,6 @@ func (b *buffer) skip(bs byte) error { return io.EOF } -// skipAny moves the index until it encounters one of the given set of bytes. -func (b *buffer) skipAny(endTokens map[byte]bool) error { - for b.index < b.length { - if _, exists := endTokens[b.data[b.index]]; exists { - return nil - } - - b.index++ - } - - // build error message - var tokens []string - for token := range endTokens { - tokens = append(tokens, string(token)) - } - - return ufmt.Errorf( - "EOF reached before encountering one of the expected tokens: %s", - strings.Join(tokens, ", "), - ) -} - // skipAndReturnIndex moves the buffer index forward by one and returns the new index. func (b *buffer) skipAndReturnIndex() (int, error) { err := b.step() @@ -165,7 +142,7 @@ func (b *buffer) skipUntil(endTokens map[byte]bool) (int, error) { // significantTokens is a map where the keys are the significant characters in a JSON path. // The values in the map are all true, which allows us to use the map as a set for quick lookups. -var significantTokens = map[byte]bool{ +var significantTokens = [256]bool{ dot: true, // access properties of an object dollarSign: true, // root object atSign: true, // current object @@ -174,7 +151,7 @@ var significantTokens = map[byte]bool{ } // filterTokens stores the filter expression tokens. -var filterTokens = map[byte]bool{ +var filterTokens = [256]bool{ aesterisk: true, // wildcard andSign: true, orSign: true, @@ -186,7 +163,7 @@ func (b *buffer) skipToNextSignificantToken() { for b.index < b.length { current := b.data[b.index] - if _, ok := significantTokens[current]; ok { + if significantTokens[current] { break } @@ -205,7 +182,7 @@ func (b *buffer) backslash() bool { count := 0 for i := b.index - 1; ; i-- { - if i >= b.length || b.data[i] != backSlash { + if b.data[i] != backSlash { break } @@ -220,7 +197,7 @@ func (b *buffer) backslash() bool { } // numIndex holds a map of valid numeric characters -var numIndex = map[byte]bool{ +var numIndex = [256]bool{ '0': true, '1': true, '2': true, @@ -255,11 +232,11 @@ func (b *buffer) pathToken() error { } if err := b.skip(c); err != nil { - return errors.New("unmatched quote in path") + return errUnmatchedQuotePath } if b.index >= b.length { - return errors.New("unmatched quote in path") + return errUnmatchedQuotePath } case c == bracketOpen || c == parenOpen: @@ -269,7 +246,7 @@ func (b *buffer) pathToken() error { case c == bracketClose || c == parenClose: inToken = true if len(stack) == 0 || (c == bracketClose && stack[len(stack)-1] != bracketOpen) || (c == parenClose && stack[len(stack)-1] != parenOpen) { - return errors.New("mismatched bracket or parenthesis") + return errUnmatchedParenthesis } stack = stack[:len(stack)-1] @@ -284,7 +261,7 @@ func (b *buffer) pathToken() error { inToken = true inNumber = true } else if !inToken { - return errors.New("unexpected operator at start of token") + return errInvalidToken } default: @@ -300,7 +277,7 @@ func (b *buffer) pathToken() error { end: if len(stack) != 0 { - return errors.New("unclosed bracket or parenthesis at end of path") + return errUnmatchedParenthesis } if first == b.index { @@ -315,15 +292,15 @@ end: } func pathStateContainsValidPathToken(c byte) bool { - if _, ok := significantTokens[c]; ok { + if significantTokens[c] { return true } - if _, ok := filterTokens[c]; ok { + if filterTokens[c] { return true } - if _, ok := numIndex[c]; ok { + if numIndex[c] { return true } @@ -342,7 +319,7 @@ func (b *buffer) numeric(token bool) error { for ; b.index < b.length; b.index++ { b.class = b.getClasses(doubleQuote) if b.class == __ { - return errors.New("invalid token found while parsing path") + return errInvalidToken } b.state = StateTransitionTable[b.last][b.class] @@ -351,7 +328,7 @@ func (b *buffer) numeric(token bool) error { break } - return errors.New("invalid token found while parsing path") + return errInvalidToken } if b.state < __ { @@ -366,7 +343,7 @@ func (b *buffer) numeric(token bool) error { } if b.last != ZE && b.last != IN && b.last != FR && b.last != E3 { - return errors.New("invalid token found while parsing path") + return errInvalidToken } return nil @@ -407,12 +384,12 @@ func (b *buffer) string(search byte, token bool) error { b.class = b.getClasses(search) if b.class == __ { - return errors.New("invalid token found while parsing path") + return errInvalidToken } b.state = StateTransitionTable[b.last][b.class] if b.state == __ { - return errors.New("invalid token found while parsing path") + return errInvalidToken } if b.state < __ { @@ -431,11 +408,11 @@ func (b *buffer) word(bs []byte) error { max := len(bs) index := 0 - for ; b.index < b.length; b.index++ { + for ; b.index < b.length && index < max; b.index++ { c = b.data[b.index] if c != bs[index] { - return errors.New("invalid token found while parsing path") + return errInvalidToken } index++ @@ -445,7 +422,7 @@ func (b *buffer) word(bs []byte) error { } if index != max { - return errors.New("invalid token found while parsing path") + return errInvalidToken } return nil diff --git a/examples/gno.land/p/demo/json/buffer_test.gno b/examples/gno.land/p/demo/json/buffer_test.gno index b8dce390a61..f4102040be5 100644 --- a/examples/gno.land/p/demo/json/buffer_test.gno +++ b/examples/gno.land/p/demo/json/buffer_test.gno @@ -1,6 +1,8 @@ package json -import "testing" +import ( + "testing" +) func TestBufferCurrent(t *testing.T) { tests := []struct { @@ -242,37 +244,6 @@ func TestBufferSkip(t *testing.T) { } } -func TestBufferSkipAny(t *testing.T) { - tests := []struct { - name string - buffer *buffer - s map[byte]bool - wantErr bool - }{ - { - name: "Skip any valid byte", - buffer: &buffer{data: []byte("test"), length: 4, index: 0}, - s: map[byte]bool{'e': true, 'o': true}, - wantErr: false, - }, - { - name: "Skip any to EOF", - buffer: &buffer{data: []byte("test"), length: 4, index: 0}, - s: map[byte]bool{'x': true, 'y': true}, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.buffer.skipAny(tt.s) - if (err != nil) != tt.wantErr { - t.Errorf("buffer.skipAny() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - func TestSkipToNextSignificantToken(t *testing.T) { tests := []struct { name string diff --git a/examples/gno.land/p/demo/json/builder.gno b/examples/gno.land/p/demo/json/builder.gno new file mode 100644 index 00000000000..4693d5ec550 --- /dev/null +++ b/examples/gno.land/p/demo/json/builder.gno @@ -0,0 +1,89 @@ +package json + +type NodeBuilder struct { + node *Node +} + +func Builder() *NodeBuilder { + return &NodeBuilder{node: ObjectNode("", nil)} +} + +func (b *NodeBuilder) WriteString(key, value string) *NodeBuilder { + b.node.AppendObject(key, StringNode("", value)) + return b +} + +func (b *NodeBuilder) WriteNumber(key string, value float64) *NodeBuilder { + b.node.AppendObject(key, NumberNode("", value)) + return b +} + +func (b *NodeBuilder) WriteBool(key string, value bool) *NodeBuilder { + b.node.AppendObject(key, BoolNode("", value)) + return b +} + +func (b *NodeBuilder) WriteNull(key string) *NodeBuilder { + b.node.AppendObject(key, NullNode("")) + return b +} + +func (b *NodeBuilder) WriteObject(key string, fn func(*NodeBuilder)) *NodeBuilder { + nestedBuilder := &NodeBuilder{node: ObjectNode("", nil)} + fn(nestedBuilder) + b.node.AppendObject(key, nestedBuilder.node) + return b +} + +func (b *NodeBuilder) WriteArray(key string, fn func(*ArrayBuilder)) *NodeBuilder { + arrayBuilder := &ArrayBuilder{nodes: []*Node{}} + fn(arrayBuilder) + b.node.AppendObject(key, ArrayNode("", arrayBuilder.nodes)) + return b +} + +func (b *NodeBuilder) Node() *Node { + return b.node +} + +type ArrayBuilder struct { + nodes []*Node +} + +func (ab *ArrayBuilder) WriteString(value string) *ArrayBuilder { + ab.nodes = append(ab.nodes, StringNode("", value)) + return ab +} + +func (ab *ArrayBuilder) WriteNumber(value float64) *ArrayBuilder { + ab.nodes = append(ab.nodes, NumberNode("", value)) + return ab +} + +func (ab *ArrayBuilder) WriteInt(value int) *ArrayBuilder { + return ab.WriteNumber(float64(value)) +} + +func (ab *ArrayBuilder) WriteBool(value bool) *ArrayBuilder { + ab.nodes = append(ab.nodes, BoolNode("", value)) + return ab +} + +func (ab *ArrayBuilder) WriteNull() *ArrayBuilder { + ab.nodes = append(ab.nodes, NullNode("")) + return ab +} + +func (ab *ArrayBuilder) WriteObject(fn func(*NodeBuilder)) *ArrayBuilder { + nestedBuilder := &NodeBuilder{node: ObjectNode("", nil)} + fn(nestedBuilder) + ab.nodes = append(ab.nodes, nestedBuilder.node) + return ab +} + +func (ab *ArrayBuilder) WriteArray(fn func(*ArrayBuilder)) *ArrayBuilder { + nestedArrayBuilder := &ArrayBuilder{nodes: []*Node{}} + fn(nestedArrayBuilder) + ab.nodes = append(ab.nodes, ArrayNode("", nestedArrayBuilder.nodes)) + return ab +} diff --git a/examples/gno.land/p/demo/json/builder_test.gno b/examples/gno.land/p/demo/json/builder_test.gno new file mode 100644 index 00000000000..4c882d0d6c8 --- /dev/null +++ b/examples/gno.land/p/demo/json/builder_test.gno @@ -0,0 +1,103 @@ +package json + +import ( + "testing" +) + +func TestNodeBuilder(t *testing.T) { + tests := []struct { + name string + build func() *Node + expected string + }{ + { + name: "plain object", + build: func() *Node { + return Builder(). + WriteString("name", "Alice"). + WriteNumber("age", 30). + WriteBool("is_student", false). + Node() + }, + expected: `{"name":"Alice","age":30,"is_student":false}`, + }, + { + name: "nested object", + build: func() *Node { + return Builder(). + WriteString("name", "Alice"). + WriteObject("address", func(b *NodeBuilder) { + b.WriteString("city", "New York"). + WriteNumber("zipcode", 10001) + }). + Node() + }, + expected: `{"name":"Alice","address":{"city":"New York","zipcode":10001}}`, + }, + { + name: "null node", + build: func() *Node { + return Builder().WriteNull("foo").Node() + }, + expected: `{"foo":null}`, + }, + { + name: "array node", + build: func() *Node { + return Builder(). + WriteArray("items", func(ab *ArrayBuilder) { + ab.WriteString("item1"). + WriteString("item2"). + WriteString("item3") + }). + Node() + }, + expected: `{"items":["item1","item2","item3"]}`, + }, + { + name: "array with objects", + build: func() *Node { + return Builder(). + WriteArray("users", func(ab *ArrayBuilder) { + ab.WriteObject(func(b *NodeBuilder) { + b.WriteString("name", "Bob"). + WriteNumber("age", 25) + }). + WriteObject(func(b *NodeBuilder) { + b.WriteString("name", "Carol"). + WriteNumber("age", 27) + }) + }). + Node() + }, + expected: `{"users":[{"name":"Bob","age":25},{"name":"Carol","age":27}]}`, + }, + { + name: "array with various types", + build: func() *Node { + return Builder(). + WriteArray("values", func(ab *ArrayBuilder) { + ab.WriteString("item1"). + WriteNumber(123). + WriteBool(true). + WriteNull() + }). + Node() + }, + expected: `{"values":["item1",123,true,null]}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + node := tt.build() + value, err := Marshal(node) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + if string(value) != tt.expected { + t.Errorf("expected %s, got %s", tt.expected, string(value)) + } + }) + } +} diff --git a/examples/gno.land/p/demo/json/decode_test.gno b/examples/gno.land/p/demo/json/decode_test.gno index 8aad07169f2..dc92f1f84cd 100644 --- a/examples/gno.land/p/demo/json/decode_test.gno +++ b/examples/gno.land/p/demo/json/decode_test.gno @@ -8,8 +8,8 @@ import ( type testNode struct { name string input []byte - _type ValueType value []byte + _type ValueType } func simpleValid(test *testNode, t *testing.T) { diff --git a/examples/gno.land/p/demo/json/eisel_lemire/eisel_lemire.gno b/examples/gno.land/p/demo/json/eisel_lemire/eisel_lemire.gno deleted file mode 100644 index 6a29f7f1350..00000000000 --- a/examples/gno.land/p/demo/json/eisel_lemire/eisel_lemire.gno +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright 2020 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 eisel_lemire - -// This file implements the Eisel-Lemire ParseFloat algorithm, published in -// 2020 and discussed extensively at -// https://nigeltao.github.io/blog/2020/eisel-lemire.html -// -// The original C++ implementation is at -// https://github.com/lemire/fast_double_parser/blob/644bef4306059d3be01a04e77d3cc84b379c596f/include/fast_double_parser.h#L840 -// -// This Go re-implementation closely follows the C re-implementation at -// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/internal/cgen/base/floatconv-submodule-code.c#L990 -// -// Additional testing (on over several million test strings) is done by -// https://github.com/nigeltao/parse-number-fxx-test-data/blob/5280dcfccf6d0b02a65ae282dad0b6d9de50e039/script/test-go-strconv.go - -import ( - "math" - "math/bits" -) - -const ( - float32ExponentBias = 127 - float64ExponentBias = 1023 -) - -// eiselLemire64 parses a floating-point number from its mantissa and exponent representation. -// This implementation is based on the Eisel-Lemire ParseFloat algorithm, which is efficient -// and precise for converting strings to floating-point numbers. -// -// Arguments: -// man (uint64): The mantissa part of the floating-point number. -// exp10 (int): The exponent part, representing the power of 10. -// neg (bool): Indicates if the number is negative. -// -// Returns: -// f (float64): The parsed floating-point number. -// ok (bool): Indicates whether the parsing was successful. -// -// The function starts by handling special cases, such as zero mantissa. -// It then checks if the exponent is within the allowed range. -// After that, it normalizes the mantissa by left-shifting it to fill -// the leading zeros. This is followed by the main algorithm logic that -// converts the normalized mantissa and exponent into a 64-bit floating-point number. -// The function returns this number along with a boolean indicating the success of the operation. -func EiselLemire64(man uint64, exp10 int, neg bool) (f float64, ok bool) { - // The terse comments in this function body refer to sections of the - // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. - - // Exp10 Range. - if man == 0 { - if neg { - f = math.Float64frombits(0x80000000_00000000) // Negative zero. - } - - return f, true - } - - if exp10 < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < exp10 { - return 0, false - } - - // Normalization. - clz := bits.LeadingZeros64(man) - man <<= uint(clz) - retExp2 := uint64(217706*exp10>>16+64+float64ExponentBias) - uint64(clz) - - // Multiplication. - xHi, xLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][1]) - - // Wider Approximation. - if xHi&0x1FF == 0x1FF && xLo+man < man { - yHi, yLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][0]) - mergedHi, mergedLo := xHi, xLo+yHi - if mergedLo < xLo { - mergedHi++ - } - - if mergedHi&0x1FF == 0x1FF && mergedLo+1 == 0 && yLo+man < man { - return 0, false - } - - xHi, xLo = mergedHi, mergedLo - } - - // Shifting to 54 Bits. - msb := xHi >> 63 - retMantissa := xHi >> (msb + 9) - retExp2 -= 1 ^ msb - - // Half-way Ambiguity. - if xLo == 0 && xHi&0x1FF == 0 && retMantissa&3 == 1 { - return 0, false - } - - // From 54 to 53 Bits. - retMantissa += retMantissa & 1 - retMantissa >>= 1 - if retMantissa>>53 > 0 { - retMantissa >>= 1 - retExp2 += 1 - } - - // retExp2 is a uint64. Zero or underflow means that we're in subnormal - // float64 space. 0x7FF or above means that we're in Inf/NaN float64 space. - // - // The if block is equivalent to (but has fewer branches than): - // if retExp2 <= 0 || retExp2 >= 0x7FF { etc } - if retExp2-1 >= 0x7FF-1 { - return 0, false - } - - retBits := retExp2<<52 | retMantissa&0x000FFFFF_FFFFFFFF - if neg { - retBits |= 0x80000000_00000000 - } - - return math.Float64frombits(retBits), true -} - -// detailedPowersOfTen{Min,Max}Exp10 is the power of 10 represented by the -// first and last rows of detailedPowersOfTen. Both bounds are inclusive. -const ( - detailedPowersOfTenMinExp10 = -348 - detailedPowersOfTenMaxExp10 = +347 -) - -// detailedPowersOfTen contains 128-bit mantissa approximations (rounded down) -// to the powers of 10. For example: -// -// - 1e43 ≈ (0xE596B7B0_C643C719 * (2 ** 79)) -// - 1e43 = (0xE596B7B0_C643C719_6D9CCD05_D0000000 * (2 ** 15)) -// -// The mantissas are explicitly listed. The exponents are implied by a linear -// expression with slope 217706.0/65536.0 ≈ log(10)/log(2). -// -// The table was generated by -// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/script/print-mpb-powers-of-10.go -var detailedPowersOfTen = [...][2]uint64{ - {0x1732C869CD60E453, 0xFA8FD5A0081C0288}, // 1e-348 - {0x0E7FBD42205C8EB4, 0x9C99E58405118195}, // 1e-347 - {0x521FAC92A873B261, 0xC3C05EE50655E1FA}, // 1e-346 - {0xE6A797B752909EF9, 0xF4B0769E47EB5A78}, // 1e-345 - {0x9028BED2939A635C, 0x98EE4A22ECF3188B}, // 1e-344 - {0x7432EE873880FC33, 0xBF29DCABA82FDEAE}, // 1e-343 - {0x113FAA2906A13B3F, 0xEEF453D6923BD65A}, // 1e-342 - {0x4AC7CA59A424C507, 0x9558B4661B6565F8}, // 1e-341 - {0x5D79BCF00D2DF649, 0xBAAEE17FA23EBF76}, // 1e-340 - {0xF4D82C2C107973DC, 0xE95A99DF8ACE6F53}, // 1e-339 - {0x79071B9B8A4BE869, 0x91D8A02BB6C10594}, // 1e-338 - {0x9748E2826CDEE284, 0xB64EC836A47146F9}, // 1e-337 - {0xFD1B1B2308169B25, 0xE3E27A444D8D98B7}, // 1e-336 - {0xFE30F0F5E50E20F7, 0x8E6D8C6AB0787F72}, // 1e-335 - {0xBDBD2D335E51A935, 0xB208EF855C969F4F}, // 1e-334 - {0xAD2C788035E61382, 0xDE8B2B66B3BC4723}, // 1e-333 - {0x4C3BCB5021AFCC31, 0x8B16FB203055AC76}, // 1e-332 - {0xDF4ABE242A1BBF3D, 0xADDCB9E83C6B1793}, // 1e-331 - {0xD71D6DAD34A2AF0D, 0xD953E8624B85DD78}, // 1e-330 - {0x8672648C40E5AD68, 0x87D4713D6F33AA6B}, // 1e-329 - {0x680EFDAF511F18C2, 0xA9C98D8CCB009506}, // 1e-328 - {0x0212BD1B2566DEF2, 0xD43BF0EFFDC0BA48}, // 1e-327 - {0x014BB630F7604B57, 0x84A57695FE98746D}, // 1e-326 - {0x419EA3BD35385E2D, 0xA5CED43B7E3E9188}, // 1e-325 - {0x52064CAC828675B9, 0xCF42894A5DCE35EA}, // 1e-324 - {0x7343EFEBD1940993, 0x818995CE7AA0E1B2}, // 1e-323 - {0x1014EBE6C5F90BF8, 0xA1EBFB4219491A1F}, // 1e-322 - {0xD41A26E077774EF6, 0xCA66FA129F9B60A6}, // 1e-321 - {0x8920B098955522B4, 0xFD00B897478238D0}, // 1e-320 - {0x55B46E5F5D5535B0, 0x9E20735E8CB16382}, // 1e-319 - {0xEB2189F734AA831D, 0xC5A890362FDDBC62}, // 1e-318 - {0xA5E9EC7501D523E4, 0xF712B443BBD52B7B}, // 1e-317 - {0x47B233C92125366E, 0x9A6BB0AA55653B2D}, // 1e-316 - {0x999EC0BB696E840A, 0xC1069CD4EABE89F8}, // 1e-315 - {0xC00670EA43CA250D, 0xF148440A256E2C76}, // 1e-314 - {0x380406926A5E5728, 0x96CD2A865764DBCA}, // 1e-313 - {0xC605083704F5ECF2, 0xBC807527ED3E12BC}, // 1e-312 - {0xF7864A44C633682E, 0xEBA09271E88D976B}, // 1e-311 - {0x7AB3EE6AFBE0211D, 0x93445B8731587EA3}, // 1e-310 - {0x5960EA05BAD82964, 0xB8157268FDAE9E4C}, // 1e-309 - {0x6FB92487298E33BD, 0xE61ACF033D1A45DF}, // 1e-308 - {0xA5D3B6D479F8E056, 0x8FD0C16206306BAB}, // 1e-307 - {0x8F48A4899877186C, 0xB3C4F1BA87BC8696}, // 1e-306 - {0x331ACDABFE94DE87, 0xE0B62E2929ABA83C}, // 1e-305 - {0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925}, // 1e-304 - {0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F}, // 1e-303 - {0xC9E82CD9F69D6150, 0xDB71E91432B1A24A}, // 1e-302 - {0xBE311C083A225CD2, 0x892731AC9FAF056E}, // 1e-301 - {0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA}, // 1e-300 - {0x092CBBCCDAD5B108, 0xD64D3D9DB981787D}, // 1e-299 - {0x25BBF56008C58EA5, 0x85F0468293F0EB4E}, // 1e-298 - {0xAF2AF2B80AF6F24E, 0xA76C582338ED2621}, // 1e-297 - {0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA}, // 1e-296 - {0x50D98D9FC890ED4D, 0x82CCA4DB847945CA}, // 1e-295 - {0xE50FF107BAB528A0, 0xA37FCE126597973C}, // 1e-294 - {0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C}, // 1e-293 - {0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F}, // 1e-292 - {0x77B191618C54E9AC, 0x9FAACF3DF73609B1}, // 1e-291 - {0xD59DF5B9EF6A2417, 0xC795830D75038C1D}, // 1e-290 - {0x4B0573286B44AD1D, 0xF97AE3D0D2446F25}, // 1e-289 - {0x4EE367F9430AEC32, 0x9BECCE62836AC577}, // 1e-288 - {0x229C41F793CDA73F, 0xC2E801FB244576D5}, // 1e-287 - {0x6B43527578C1110F, 0xF3A20279ED56D48A}, // 1e-286 - {0x830A13896B78AAA9, 0x9845418C345644D6}, // 1e-285 - {0x23CC986BC656D553, 0xBE5691EF416BD60C}, // 1e-284 - {0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F}, // 1e-283 - {0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39}, // 1e-282 - {0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07}, // 1e-281 - {0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9}, // 1e-280 - {0x23100809B9C21FA1, 0x91376C36D99995BE}, // 1e-279 - {0xABD40A0C2832A78A, 0xB58547448FFFFB2D}, // 1e-278 - {0x16C90C8F323F516C, 0xE2E69915B3FFF9F9}, // 1e-277 - {0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B}, // 1e-276 - {0x99CD11CFDF41779C, 0xB1442798F49FFB4A}, // 1e-275 - {0x40405643D711D583, 0xDD95317F31C7FA1D}, // 1e-274 - {0x482835EA666B2572, 0x8A7D3EEF7F1CFC52}, // 1e-273 - {0xDA3243650005EECF, 0xAD1C8EAB5EE43B66}, // 1e-272 - {0x90BED43E40076A82, 0xD863B256369D4A40}, // 1e-271 - {0x5A7744A6E804A291, 0x873E4F75E2224E68}, // 1e-270 - {0x711515D0A205CB36, 0xA90DE3535AAAE202}, // 1e-269 - {0x0D5A5B44CA873E03, 0xD3515C2831559A83}, // 1e-268 - {0xE858790AFE9486C2, 0x8412D9991ED58091}, // 1e-267 - {0x626E974DBE39A872, 0xA5178FFF668AE0B6}, // 1e-266 - {0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3}, // 1e-265 - {0x7CE66634BC9D0B99, 0x80FA687F881C7F8E}, // 1e-264 - {0x1C1FFFC1EBC44E80, 0xA139029F6A239F72}, // 1e-263 - {0xA327FFB266B56220, 0xC987434744AC874E}, // 1e-262 - {0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922}, // 1e-261 - {0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5}, // 1e-260 - {0xCB550FB4384D21D3, 0xC4CE17B399107C22}, // 1e-259 - {0x7E2A53A146606A48, 0xF6019DA07F549B2B}, // 1e-258 - {0x2EDA7444CBFC426D, 0x99C102844F94E0FB}, // 1e-257 - {0xFA911155FEFB5308, 0xC0314325637A1939}, // 1e-256 - {0x793555AB7EBA27CA, 0xF03D93EEBC589F88}, // 1e-255 - {0x4BC1558B2F3458DE, 0x96267C7535B763B5}, // 1e-254 - {0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2}, // 1e-253 - {0x465E15A979C1CADC, 0xEA9C227723EE8BCB}, // 1e-252 - {0x0BFACD89EC191EC9, 0x92A1958A7675175F}, // 1e-251 - {0xCEF980EC671F667B, 0xB749FAED14125D36}, // 1e-250 - {0x82B7E12780E7401A, 0xE51C79A85916F484}, // 1e-249 - {0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2}, // 1e-248 - {0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07}, // 1e-247 - {0x67A791E093E1D49A, 0xDFBDCECE67006AC9}, // 1e-246 - {0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD}, // 1e-245 - {0x58FAE9F773886E18, 0xAECC49914078536D}, // 1e-244 - {0xAF39A475506A899E, 0xDA7F5BF590966848}, // 1e-243 - {0x6D8406C952429603, 0x888F99797A5E012D}, // 1e-242 - {0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178}, // 1e-241 - {0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6}, // 1e-240 - {0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26}, // 1e-239 - {0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F}, // 1e-238 - {0xF13B94DAF124DA26, 0xD0601D8EFC57B08B}, // 1e-237 - {0x76C53D08D6B70858, 0x823C12795DB6CE57}, // 1e-236 - {0x54768C4B0C64CA6E, 0xA2CB1717B52481ED}, // 1e-235 - {0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268}, // 1e-234 - {0xD3F93B35435D7C4C, 0xFE5D54150B090B02}, // 1e-233 - {0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1}, // 1e-232 - {0x359AB6419CA1091B, 0xC6B8E9B0709F109A}, // 1e-231 - {0xC30163D203C94B62, 0xF867241C8CC6D4C0}, // 1e-230 - {0x79E0DE63425DCF1D, 0x9B407691D7FC44F8}, // 1e-229 - {0x985915FC12F542E4, 0xC21094364DFB5636}, // 1e-228 - {0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4}, // 1e-227 - {0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A}, // 1e-226 - {0x50C6FF782A838353, 0xBD8430BD08277231}, // 1e-225 - {0xA4F8BF5635246428, 0xECE53CEC4A314EBD}, // 1e-224 - {0x871B7795E136BE99, 0x940F4613AE5ED136}, // 1e-223 - {0x28E2557B59846E3F, 0xB913179899F68584}, // 1e-222 - {0x331AEADA2FE589CF, 0xE757DD7EC07426E5}, // 1e-221 - {0x3FF0D2C85DEF7621, 0x9096EA6F3848984F}, // 1e-220 - {0x0FED077A756B53A9, 0xB4BCA50B065ABE63}, // 1e-219 - {0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB}, // 1e-218 - {0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD}, // 1e-217 - {0xBD8D794D96AACFB3, 0xB080392CC4349DEC}, // 1e-216 - {0xECF0D7A0FC5583A0, 0xDCA04777F541C567}, // 1e-215 - {0xF41686C49DB57244, 0x89E42CAAF9491B60}, // 1e-214 - {0x311C2875C522CED5, 0xAC5D37D5B79B6239}, // 1e-213 - {0x7D633293366B828B, 0xD77485CB25823AC7}, // 1e-212 - {0xAE5DFF9C02033197, 0x86A8D39EF77164BC}, // 1e-211 - {0xD9F57F830283FDFC, 0xA8530886B54DBDEB}, // 1e-210 - {0xD072DF63C324FD7B, 0xD267CAA862A12D66}, // 1e-209 - {0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60}, // 1e-208 - {0x52D9BE85F074E608, 0xA46116538D0DEB78}, // 1e-207 - {0x67902E276C921F8B, 0xCD795BE870516656}, // 1e-206 - {0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6}, // 1e-205 - {0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3}, // 1e-204 - {0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0}, // 1e-203 - {0x796B805720085F81, 0xFAD2A4B13D1B5D6C}, // 1e-202 - {0xCBE3303674053BB0, 0x9CC3A6EEC6311A63}, // 1e-201 - {0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC}, // 1e-200 - {0xEE92FB5515482D44, 0xF4F1B4D515ACB93B}, // 1e-199 - {0x751BDD152D4D1C4A, 0x991711052D8BF3C5}, // 1e-198 - {0xD262D45A78A0635D, 0xBF5CD54678EEF0B6}, // 1e-197 - {0x86FB897116C87C34, 0xEF340A98172AACE4}, // 1e-196 - {0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E}, // 1e-195 - {0x8974836059CCA109, 0xBAE0A846D2195712}, // 1e-194 - {0x2BD1A438703FC94B, 0xE998D258869FACD7}, // 1e-193 - {0x7B6306A34627DDCF, 0x91FF83775423CC06}, // 1e-192 - {0x1A3BC84C17B1D542, 0xB67F6455292CBF08}, // 1e-191 - {0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA}, // 1e-190 - {0x547EB47B7282EE9C, 0x8E938662882AF53E}, // 1e-189 - {0xE99E619A4F23AA43, 0xB23867FB2A35B28D}, // 1e-188 - {0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31}, // 1e-187 - {0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E}, // 1e-186 - {0x9624AB50B148D445, 0xAE0B158B4738705E}, // 1e-185 - {0x3BADD624DD9B0957, 0xD98DDAEE19068C76}, // 1e-184 - {0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9}, // 1e-183 - {0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC}, // 1e-182 - {0x7647C3200069671F, 0xD47487CC8470652B}, // 1e-181 - {0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B}, // 1e-180 - {0xF468107100525890, 0xA5FB0A17C777CF09}, // 1e-179 - {0x7182148D4066EEB4, 0xCF79CC9DB955C2CC}, // 1e-178 - {0xC6F14CD848405530, 0x81AC1FE293D599BF}, // 1e-177 - {0xB8ADA00E5A506A7C, 0xA21727DB38CB002F}, // 1e-176 - {0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B}, // 1e-175 - {0x908F4A166D1DA663, 0xFD442E4688BD304A}, // 1e-174 - {0x9A598E4E043287FE, 0x9E4A9CEC15763E2E}, // 1e-173 - {0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA}, // 1e-172 - {0xD12BEE59E68EF47C, 0xF7549530E188C128}, // 1e-171 - {0x82BB74F8301958CE, 0x9A94DD3E8CF578B9}, // 1e-170 - {0xE36A52363C1FAF01, 0xC13A148E3032D6E7}, // 1e-169 - {0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1}, // 1e-168 - {0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5}, // 1e-167 - {0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE}, // 1e-166 - {0x111B495B3464AD21, 0xEBDF661791D60F56}, // 1e-165 - {0xCAB10DD900BEEC34, 0x936B9FCEBB25C995}, // 1e-164 - {0x3D5D514F40EEA742, 0xB84687C269EF3BFB}, // 1e-163 - {0x0CB4A5A3112A5112, 0xE65829B3046B0AFA}, // 1e-162 - {0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC}, // 1e-161 - {0x59ED216765690F56, 0xB3F4E093DB73A093}, // 1e-160 - {0x306869C13EC3532C, 0xE0F218B8D25088B8}, // 1e-159 - {0x1E414218C73A13FB, 0x8C974F7383725573}, // 1e-158 - {0xE5D1929EF90898FA, 0xAFBD2350644EEACF}, // 1e-157 - {0xDF45F746B74ABF39, 0xDBAC6C247D62A583}, // 1e-156 - {0x6B8BBA8C328EB783, 0x894BC396CE5DA772}, // 1e-155 - {0x066EA92F3F326564, 0xAB9EB47C81F5114F}, // 1e-154 - {0xC80A537B0EFEFEBD, 0xD686619BA27255A2}, // 1e-153 - {0xBD06742CE95F5F36, 0x8613FD0145877585}, // 1e-152 - {0x2C48113823B73704, 0xA798FC4196E952E7}, // 1e-151 - {0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0}, // 1e-150 - {0x9A984D73DBE722FB, 0x82EF85133DE648C4}, // 1e-149 - {0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5}, // 1e-148 - {0x318DF905079926A8, 0xCC963FEE10B7D1B3}, // 1e-147 - {0xFDF17746497F7052, 0xFFBBCFE994E5C61F}, // 1e-146 - {0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3}, // 1e-145 - {0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8}, // 1e-144 - {0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B}, // 1e-143 - {0x06BEA10CA65C084E, 0x9C1661A651213E2D}, // 1e-142 - {0x486E494FCFF30A62, 0xC31BFA0FE5698DB8}, // 1e-141 - {0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126}, // 1e-140 - {0xF89629465A75E01C, 0x986DDB5C6B3A76B7}, // 1e-139 - {0xF6BBB397F1135823, 0xBE89523386091465}, // 1e-138 - {0x746AA07DED582E2C, 0xEE2BA6C0678B597F}, // 1e-137 - {0xA8C2A44EB4571CDC, 0x94DB483840B717EF}, // 1e-136 - {0x92F34D62616CE413, 0xBA121A4650E4DDEB}, // 1e-135 - {0x77B020BAF9C81D17, 0xE896A0D7E51E1566}, // 1e-134 - {0x0ACE1474DC1D122E, 0x915E2486EF32CD60}, // 1e-133 - {0x0D819992132456BA, 0xB5B5ADA8AAFF80B8}, // 1e-132 - {0x10E1FFF697ED6C69, 0xE3231912D5BF60E6}, // 1e-131 - {0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F}, // 1e-130 - {0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3}, // 1e-129 - {0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0}, // 1e-128 - {0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4}, // 1e-127 - {0x86C16C98D2C953C6, 0xAD4AB7112EB3929D}, // 1e-126 - {0xE871C7BF077BA8B7, 0xD89D64D57A607744}, // 1e-125 - {0x11471CD764AD4972, 0x87625F056C7C4A8B}, // 1e-124 - {0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D}, // 1e-123 - {0x4AFF1D108D4EC2C3, 0xD389B47879823479}, // 1e-122 - {0xCEDF722A585139BA, 0x843610CB4BF160CB}, // 1e-121 - {0xC2974EB4EE658828, 0xA54394FE1EEDB8FE}, // 1e-120 - {0x733D226229FEEA32, 0xCE947A3DA6A9273E}, // 1e-119 - {0x0806357D5A3F525F, 0x811CCC668829B887}, // 1e-118 - {0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8}, // 1e-117 - {0xFC89B393DD02F0B5, 0xC9BCFF6034C13052}, // 1e-116 - {0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67}, // 1e-115 - {0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0}, // 1e-114 - {0x0A9E795E65D4DF11, 0xC5029163F384A931}, // 1e-113 - {0x4D4617B5FF4A16D5, 0xF64335BCF065D37D}, // 1e-112 - {0x504BCED1BF8E4E45, 0x99EA0196163FA42E}, // 1e-111 - {0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39}, // 1e-110 - {0x5D767327BB4E5A4C, 0xF07DA27A82C37088}, // 1e-109 - {0x3A6A07F8D510F86F, 0x964E858C91BA2655}, // 1e-108 - {0x890489F70A55368B, 0xBBE226EFB628AFEA}, // 1e-107 - {0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5}, // 1e-106 - {0x3B0B8BC90012929D, 0x92C8AE6B464FC96F}, // 1e-105 - {0x09CE6EBB40173744, 0xB77ADA0617E3BBCB}, // 1e-104 - {0xCC420A6A101D0515, 0xE55990879DDCAABD}, // 1e-103 - {0x9FA946824A12232D, 0x8F57FA54C2A9EAB6}, // 1e-102 - {0x47939822DC96ABF9, 0xB32DF8E9F3546564}, // 1e-101 - {0x59787E2B93BC56F7, 0xDFF9772470297EBD}, // 1e-100 - {0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36}, // 1e-99 - {0xEDE622920B6B23F1, 0xAEFAE51477A06B03}, // 1e-98 - {0xE95FAB368E45ECED, 0xDAB99E59958885C4}, // 1e-97 - {0x11DBCB0218EBB414, 0x88B402F7FD75539B}, // 1e-96 - {0xD652BDC29F26A119, 0xAAE103B5FCD2A881}, // 1e-95 - {0x4BE76D3346F0495F, 0xD59944A37C0752A2}, // 1e-94 - {0x6F70A4400C562DDB, 0x857FCAE62D8493A5}, // 1e-93 - {0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E}, // 1e-92 - {0x7E2000A41346A7A7, 0xD097AD07A71F26B2}, // 1e-91 - {0x8ED400668C0C28C8, 0x825ECC24C873782F}, // 1e-90 - {0x728900802F0F32FA, 0xA2F67F2DFA90563B}, // 1e-89 - {0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA}, // 1e-88 - {0xE2F610C84987BFA8, 0xFEA126B7D78186BC}, // 1e-87 - {0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436}, // 1e-86 - {0x91503D1C79720DBB, 0xC6EDE63FA05D3143}, // 1e-85 - {0x75A44C6397CE912A, 0xF8A95FCF88747D94}, // 1e-84 - {0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C}, // 1e-83 - {0xFBE85BADCE996168, 0xC24452DA229B021B}, // 1e-82 - {0xFAE27299423FB9C3, 0xF2D56790AB41C2A2}, // 1e-81 - {0xDCCD879FC967D41A, 0x97C560BA6B0919A5}, // 1e-80 - {0x5400E987BBC1C920, 0xBDB6B8E905CB600F}, // 1e-79 - {0x290123E9AAB23B68, 0xED246723473E3813}, // 1e-78 - {0xF9A0B6720AAF6521, 0x9436C0760C86E30B}, // 1e-77 - {0xF808E40E8D5B3E69, 0xB94470938FA89BCE}, // 1e-76 - {0xB60B1D1230B20E04, 0xE7958CB87392C2C2}, // 1e-75 - {0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9}, // 1e-74 - {0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828}, // 1e-73 - {0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232}, // 1e-72 - {0x579C487E5A38AD0E, 0x8D590723948A535F}, // 1e-71 - {0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837}, // 1e-70 - {0xF8E431456CF88E65, 0xDCDB1B2798182244}, // 1e-69 - {0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B}, // 1e-68 - {0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5}, // 1e-67 - {0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177}, // 1e-66 - {0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA}, // 1e-65 - {0x3F2398D747B36224, 0xA87FEA27A539E9A5}, // 1e-64 - {0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E}, // 1e-63 - {0x1953CF68300424AC, 0x83A3EEEEF9153E89}, // 1e-62 - {0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B}, // 1e-61 - {0x3792F412CB06794D, 0xCDB02555653131B6}, // 1e-60 - {0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11}, // 1e-59 - {0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6}, // 1e-58 - {0xF245825A5A445275, 0xC8DE047564D20A8B}, // 1e-57 - {0xEED6E2F0F0D56712, 0xFB158592BE068D2E}, // 1e-56 - {0x55464DD69685606B, 0x9CED737BB6C4183D}, // 1e-55 - {0xAA97E14C3C26B886, 0xC428D05AA4751E4C}, // 1e-54 - {0xD53DD99F4B3066A8, 0xF53304714D9265DF}, // 1e-53 - {0xE546A8038EFE4029, 0x993FE2C6D07B7FAB}, // 1e-52 - {0xDE98520472BDD033, 0xBF8FDB78849A5F96}, // 1e-51 - {0x963E66858F6D4440, 0xEF73D256A5C0F77C}, // 1e-50 - {0xDDE7001379A44AA8, 0x95A8637627989AAD}, // 1e-49 - {0x5560C018580D5D52, 0xBB127C53B17EC159}, // 1e-48 - {0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF}, // 1e-47 - {0xCAB3961304CA70E8, 0x9226712162AB070D}, // 1e-46 - {0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1}, // 1e-45 - {0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05}, // 1e-44 - {0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3}, // 1e-43 - {0x55F038B237591ED3, 0xB267ED1940F1C61C}, // 1e-42 - {0x6B6C46DEC52F6688, 0xDF01E85F912E37A3}, // 1e-41 - {0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6}, // 1e-40 - {0xABEC975E0A0D081A, 0xAE397D8AA96C1B77}, // 1e-39 - {0x96E7BD358C904A21, 0xD9C7DCED53C72255}, // 1e-38 - {0x7E50D64177DA2E54, 0x881CEA14545C7575}, // 1e-37 - {0xDDE50BD1D5D0B9E9, 0xAA242499697392D2}, // 1e-36 - {0x955E4EC64B44E864, 0xD4AD2DBFC3D07787}, // 1e-35 - {0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4}, // 1e-34 - {0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61}, // 1e-33 - {0x67DE18EDA5814AF2, 0xCFB11EAD453994BA}, // 1e-32 - {0x80EACF948770CED7, 0x81CEB32C4B43FCF4}, // 1e-31 - {0xA1258379A94D028D, 0xA2425FF75E14FC31}, // 1e-30 - {0x096EE45813A04330, 0xCAD2F7F5359A3B3E}, // 1e-29 - {0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D}, // 1e-28 - {0x775EA264CF55347D, 0x9E74D1B791E07E48}, // 1e-27 - {0x95364AFE032A819D, 0xC612062576589DDA}, // 1e-26 - {0x3A83DDBD83F52204, 0xF79687AED3EEC551}, // 1e-25 - {0xC4926A9672793542, 0x9ABE14CD44753B52}, // 1e-24 - {0x75B7053C0F178293, 0xC16D9A0095928A27}, // 1e-23 - {0x5324C68B12DD6338, 0xF1C90080BAF72CB1}, // 1e-22 - {0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE}, // 1e-21 - {0x88F4BB1CA6BCF584, 0xBCE5086492111AEA}, // 1e-20 - {0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5}, // 1e-19 - {0x3AFF322E62439FCF, 0x9392EE8E921D5D07}, // 1e-18 - {0x09BEFEB9FAD487C2, 0xB877AA3236A4B449}, // 1e-17 - {0x4C2EBE687989A9B3, 0xE69594BEC44DE15B}, // 1e-16 - {0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9}, // 1e-15 - {0x538484C19EF38C94, 0xB424DC35095CD80F}, // 1e-14 - {0x2865A5F206B06FB9, 0xE12E13424BB40E13}, // 1e-13 - {0xF93F87B7442E45D3, 0x8CBCCC096F5088CB}, // 1e-12 - {0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE}, // 1e-11 - {0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE}, // 1e-10 - {0x31680A88F8953030, 0x89705F4136B4A597}, // 1e-9 - {0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC}, // 1e-8 - {0x3D32907604691B4C, 0xD6BF94D5E57A42BC}, // 1e-7 - {0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5}, // 1e-6 - {0x0FCF80DC33721D53, 0xA7C5AC471B478423}, // 1e-5 - {0xD3C36113404EA4A8, 0xD1B71758E219652B}, // 1e-4 - {0x645A1CAC083126E9, 0x83126E978D4FDF3B}, // 1e-3 - {0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A}, // 1e-2 - {0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC}, // 1e-1 - {0x0000000000000000, 0x8000000000000000}, // 1e0 - {0x0000000000000000, 0xA000000000000000}, // 1e1 - {0x0000000000000000, 0xC800000000000000}, // 1e2 - {0x0000000000000000, 0xFA00000000000000}, // 1e3 - {0x0000000000000000, 0x9C40000000000000}, // 1e4 - {0x0000000000000000, 0xC350000000000000}, // 1e5 - {0x0000000000000000, 0xF424000000000000}, // 1e6 - {0x0000000000000000, 0x9896800000000000}, // 1e7 - {0x0000000000000000, 0xBEBC200000000000}, // 1e8 - {0x0000000000000000, 0xEE6B280000000000}, // 1e9 - {0x0000000000000000, 0x9502F90000000000}, // 1e10 - {0x0000000000000000, 0xBA43B74000000000}, // 1e11 - {0x0000000000000000, 0xE8D4A51000000000}, // 1e12 - {0x0000000000000000, 0x9184E72A00000000}, // 1e13 - {0x0000000000000000, 0xB5E620F480000000}, // 1e14 - {0x0000000000000000, 0xE35FA931A0000000}, // 1e15 - {0x0000000000000000, 0x8E1BC9BF04000000}, // 1e16 - {0x0000000000000000, 0xB1A2BC2EC5000000}, // 1e17 - {0x0000000000000000, 0xDE0B6B3A76400000}, // 1e18 - {0x0000000000000000, 0x8AC7230489E80000}, // 1e19 - {0x0000000000000000, 0xAD78EBC5AC620000}, // 1e20 - {0x0000000000000000, 0xD8D726B7177A8000}, // 1e21 - {0x0000000000000000, 0x878678326EAC9000}, // 1e22 - {0x0000000000000000, 0xA968163F0A57B400}, // 1e23 - {0x0000000000000000, 0xD3C21BCECCEDA100}, // 1e24 - {0x0000000000000000, 0x84595161401484A0}, // 1e25 - {0x0000000000000000, 0xA56FA5B99019A5C8}, // 1e26 - {0x0000000000000000, 0xCECB8F27F4200F3A}, // 1e27 - {0x4000000000000000, 0x813F3978F8940984}, // 1e28 - {0x5000000000000000, 0xA18F07D736B90BE5}, // 1e29 - {0xA400000000000000, 0xC9F2C9CD04674EDE}, // 1e30 - {0x4D00000000000000, 0xFC6F7C4045812296}, // 1e31 - {0xF020000000000000, 0x9DC5ADA82B70B59D}, // 1e32 - {0x6C28000000000000, 0xC5371912364CE305}, // 1e33 - {0xC732000000000000, 0xF684DF56C3E01BC6}, // 1e34 - {0x3C7F400000000000, 0x9A130B963A6C115C}, // 1e35 - {0x4B9F100000000000, 0xC097CE7BC90715B3}, // 1e36 - {0x1E86D40000000000, 0xF0BDC21ABB48DB20}, // 1e37 - {0x1314448000000000, 0x96769950B50D88F4}, // 1e38 - {0x17D955A000000000, 0xBC143FA4E250EB31}, // 1e39 - {0x5DCFAB0800000000, 0xEB194F8E1AE525FD}, // 1e40 - {0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE}, // 1e41 - {0xF14A3D9E40000000, 0xB7ABC627050305AD}, // 1e42 - {0x6D9CCD05D0000000, 0xE596B7B0C643C719}, // 1e43 - {0xE4820023A2000000, 0x8F7E32CE7BEA5C6F}, // 1e44 - {0xDDA2802C8A800000, 0xB35DBF821AE4F38B}, // 1e45 - {0xD50B2037AD200000, 0xE0352F62A19E306E}, // 1e46 - {0x4526F422CC340000, 0x8C213D9DA502DE45}, // 1e47 - {0x9670B12B7F410000, 0xAF298D050E4395D6}, // 1e48 - {0x3C0CDD765F114000, 0xDAF3F04651D47B4C}, // 1e49 - {0xA5880A69FB6AC800, 0x88D8762BF324CD0F}, // 1e50 - {0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053}, // 1e51 - {0x72A4904598D6D880, 0xD5D238A4ABE98068}, // 1e52 - {0x47A6DA2B7F864750, 0x85A36366EB71F041}, // 1e53 - {0x999090B65F67D924, 0xA70C3C40A64E6C51}, // 1e54 - {0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765}, // 1e55 - {0xBFF8F10E7A8921A4, 0x82818F1281ED449F}, // 1e56 - {0xAFF72D52192B6A0D, 0xA321F2D7226895C7}, // 1e57 - {0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39}, // 1e58 - {0x02F236D04753D5B4, 0xFEE50B7025C36A08}, // 1e59 - {0x01D762422C946590, 0x9F4F2726179A2245}, // 1e60 - {0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6}, // 1e61 - {0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B}, // 1e62 - {0x63CC55F49F88EB2F, 0x9B934C3B330C8577}, // 1e63 - {0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5}, // 1e64 - {0x8BEF464E3945EF7A, 0xF316271C7FC3908A}, // 1e65 - {0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56}, // 1e66 - {0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC}, // 1e67 - {0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27}, // 1e68 - {0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8}, // 1e69 - {0xB3E2FD538E122B44, 0xB975D6B6EE39E436}, // 1e70 - {0x60DBBCA87196B616, 0xE7D34C64A9C85D44}, // 1e71 - {0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A}, // 1e72 - {0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD}, // 1e73 - {0xC696963C7EED2DD1, 0xE264589A4DCDAB14}, // 1e74 - {0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC}, // 1e75 - {0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8}, // 1e76 - {0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912}, // 1e77 - {0x6E3569326C784337, 0x8A2DBF142DFCC7AB}, // 1e78 - {0x49C2C37F07965404, 0xACB92ED9397BF996}, // 1e79 - {0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB}, // 1e80 - {0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD}, // 1e81 - {0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC}, // 1e82 - {0xF50A3FA490C30190, 0xD2D80DB02AABD62B}, // 1e83 - {0x792667C6DA79E0FA, 0x83C7088E1AAB65DB}, // 1e84 - {0x577001B891185938, 0xA4B8CAB1A1563F52}, // 1e85 - {0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26}, // 1e86 - {0x544F8158315B05B4, 0x80B05E5AC60B6178}, // 1e87 - {0x696361AE3DB1C721, 0xA0DC75F1778E39D6}, // 1e88 - {0x03BC3A19CD1E38E9, 0xC913936DD571C84C}, // 1e89 - {0x04AB48A04065C723, 0xFB5878494ACE3A5F}, // 1e90 - {0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B}, // 1e91 - {0x3BA5D0BD324F8394, 0xC45D1DF942711D9A}, // 1e92 - {0xCA8F44EC7EE36479, 0xF5746577930D6500}, // 1e93 - {0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20}, // 1e94 - {0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8}, // 1e95 - {0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2}, // 1e96 - {0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5}, // 1e97 - {0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F}, // 1e98 - {0xF52D09D71A3293BD, 0xEA1575143CF97226}, // 1e99 - {0x593C2626705F9C56, 0x924D692CA61BE758}, // 1e100 - {0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E}, // 1e101 - {0x0B6DFB9C0F956447, 0xE498F455C38B997A}, // 1e102 - {0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC}, // 1e103 - {0x58EDEC91EC2CB657, 0xB2977EE300C50FE7}, // 1e104 - {0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1}, // 1e105 - {0xBD79E0D20082EE74, 0x8B865B215899F46C}, // 1e106 - {0xECD8590680A3AA11, 0xAE67F1E9AEC07187}, // 1e107 - {0xE80E6F4820CC9495, 0xDA01EE641A708DE9}, // 1e108 - {0x3109058D147FDCDD, 0x884134FE908658B2}, // 1e109 - {0xBD4B46F0599FD415, 0xAA51823E34A7EEDE}, // 1e110 - {0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96}, // 1e111 - {0x03E2CF6BC604DDB0, 0x850FADC09923329E}, // 1e112 - {0x84DB8346B786151C, 0xA6539930BF6BFF45}, // 1e113 - {0xE612641865679A63, 0xCFE87F7CEF46FF16}, // 1e114 - {0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E}, // 1e115 - {0xE3BE5E330F38F09D, 0xA26DA3999AEF7749}, // 1e116 - {0x5CADF5BFD3072CC5, 0xCB090C8001AB551C}, // 1e117 - {0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63}, // 1e118 - {0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E}, // 1e119 - {0xB281E1FD541501B8, 0xC646D63501A1511D}, // 1e120 - {0x1F225A7CA91A4226, 0xF7D88BC24209A565}, // 1e121 - {0x3375788DE9B06958, 0x9AE757596946075F}, // 1e122 - {0x0052D6B1641C83AE, 0xC1A12D2FC3978937}, // 1e123 - {0xC0678C5DBD23A49A, 0xF209787BB47D6B84}, // 1e124 - {0xF840B7BA963646E0, 0x9745EB4D50CE6332}, // 1e125 - {0xB650E5A93BC3D898, 0xBD176620A501FBFF}, // 1e126 - {0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF}, // 1e127 - {0xC66F336C36B10137, 0x93BA47C980E98CDF}, // 1e128 - {0xB80B0047445D4184, 0xB8A8D9BBE123F017}, // 1e129 - {0xA60DC059157491E5, 0xE6D3102AD96CEC1D}, // 1e130 - {0x87C89837AD68DB2F, 0x9043EA1AC7E41392}, // 1e131 - {0x29BABE4598C311FB, 0xB454E4A179DD1877}, // 1e132 - {0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94}, // 1e133 - {0x1899E4A65F58660C, 0x8CE2529E2734BB1D}, // 1e134 - {0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4}, // 1e135 - {0x76707543F4FA1F73, 0xDC21A1171D42645D}, // 1e136 - {0x6A06494A791C53A8, 0x899504AE72497EBA}, // 1e137 - {0x0487DB9D17636892, 0xABFA45DA0EDBDE69}, // 1e138 - {0x45A9D2845D3C42B6, 0xD6F8D7509292D603}, // 1e139 - {0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2}, // 1e140 - {0x8E6CAC7768D7141E, 0xA7F26836F282B732}, // 1e141 - {0x3207D795430CD926, 0xD1EF0244AF2364FF}, // 1e142 - {0x7F44E6BD49E807B8, 0x8335616AED761F1F}, // 1e143 - {0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7}, // 1e144 - {0x36DBA887C37A8C0F, 0xCD036837130890A1}, // 1e145 - {0xC2494954DA2C9789, 0x802221226BE55A64}, // 1e146 - {0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD}, // 1e147 - {0x6F92829494E5ACC7, 0xC83553C5C8965D3D}, // 1e148 - {0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C}, // 1e149 - {0xFF2A760414536EFB, 0x9C69A97284B578D7}, // 1e150 - {0xFEF5138519684ABA, 0xC38413CF25E2D70D}, // 1e151 - {0x7EB258665FC25D69, 0xF46518C2EF5B8CD1}, // 1e152 - {0xEF2F773FFBD97A61, 0x98BF2F79D5993802}, // 1e153 - {0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603}, // 1e154 - {0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784}, // 1e155 - {0xDD945A747BF26183, 0x952AB45CFA97A0B2}, // 1e156 - {0x94F971119AEEF9E4, 0xBA756174393D88DF}, // 1e157 - {0x7A37CD5601AAB85D, 0xE912B9D1478CEB17}, // 1e158 - {0xAC62E055C10AB33A, 0x91ABB422CCB812EE}, // 1e159 - {0x577B986B314D6009, 0xB616A12B7FE617AA}, // 1e160 - {0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94}, // 1e161 - {0x14588F13BE847307, 0x8E41ADE9FBEBC27D}, // 1e162 - {0x596EB2D8AE258FC8, 0xB1D219647AE6B31C}, // 1e163 - {0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3}, // 1e164 - {0x25DE7BB9480D5854, 0x8AEC23D680043BEE}, // 1e165 - {0xAF561AA79A10AE6A, 0xADA72CCC20054AE9}, // 1e166 - {0x1B2BA1518094DA04, 0xD910F7FF28069DA4}, // 1e167 - {0x90FB44D2F05D0842, 0x87AA9AFF79042286}, // 1e168 - {0x353A1607AC744A53, 0xA99541BF57452B28}, // 1e169 - {0x42889B8997915CE8, 0xD3FA922F2D1675F2}, // 1e170 - {0x69956135FEBADA11, 0x847C9B5D7C2E09B7}, // 1e171 - {0x43FAB9837E699095, 0xA59BC234DB398C25}, // 1e172 - {0x94F967E45E03F4BB, 0xCF02B2C21207EF2E}, // 1e173 - {0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D}, // 1e174 - {0x6462D92A69731732, 0xA1BA1BA79E1632DC}, // 1e175 - {0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93}, // 1e176 - {0x5CDA735244C3D43E, 0xFCB2CB35E702AF78}, // 1e177 - {0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB}, // 1e178 - {0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916}, // 1e179 - {0x8AAD549E57273D45, 0xF6C69A72A3989F5B}, // 1e180 - {0x36AC54E2F678864B, 0x9A3C2087A63F6399}, // 1e181 - {0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F}, // 1e182 - {0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F}, // 1e183 - {0x9F644AE5A4B1B325, 0x969EB7C47859E743}, // 1e184 - {0x873D5D9F0DDE1FEE, 0xBC4665B596706114}, // 1e185 - {0xA90CB506D155A7EA, 0xEB57FF22FC0C7959}, // 1e186 - {0x09A7F12442D588F2, 0x9316FF75DD87CBD8}, // 1e187 - {0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE}, // 1e188 - {0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81}, // 1e189 - {0xF96E017D694487BC, 0x8FA475791A569D10}, // 1e190 - {0x37C981DCC395A9AC, 0xB38D92D760EC4455}, // 1e191 - {0x85BBE253F47B1417, 0xE070F78D3927556A}, // 1e192 - {0x93956D7478CCEC8E, 0x8C469AB843B89562}, // 1e193 - {0x387AC8D1970027B2, 0xAF58416654A6BABB}, // 1e194 - {0x06997B05FCC0319E, 0xDB2E51BFE9D0696A}, // 1e195 - {0x441FECE3BDF81F03, 0x88FCF317F22241E2}, // 1e196 - {0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A}, // 1e197 - {0x8A71E223D8D3B074, 0xD60B3BD56A5586F1}, // 1e198 - {0xF6872D5667844E49, 0x85C7056562757456}, // 1e199 - {0xB428F8AC016561DB, 0xA738C6BEBB12D16C}, // 1e200 - {0xE13336D701BEBA52, 0xD106F86E69D785C7}, // 1e201 - {0xECC0024661173473, 0x82A45B450226B39C}, // 1e202 - {0x27F002D7F95D0190, 0xA34D721642B06084}, // 1e203 - {0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5}, // 1e204 - {0x7E67047175A15271, 0xFF290242C83396CE}, // 1e205 - {0x0F0062C6E984D386, 0x9F79A169BD203E41}, // 1e206 - {0x52C07B78A3E60868, 0xC75809C42C684DD1}, // 1e207 - {0xA7709A56CCDF8A82, 0xF92E0C3537826145}, // 1e208 - {0x88A66076400BB691, 0x9BBCC7A142B17CCB}, // 1e209 - {0x6ACFF893D00EA435, 0xC2ABF989935DDBFE}, // 1e210 - {0x0583F6B8C4124D43, 0xF356F7EBF83552FE}, // 1e211 - {0xC3727A337A8B704A, 0x98165AF37B2153DE}, // 1e212 - {0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6}, // 1e213 - {0x1162DEF06F79DF73, 0xEDA2EE1C7064130C}, // 1e214 - {0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7}, // 1e215 - {0x6D953E2BD7173692, 0xB9A74A0637CE2EE1}, // 1e216 - {0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99}, // 1e217 - {0x1D9C9892400A22A2, 0x910AB1D4DB9914A0}, // 1e218 - {0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8}, // 1e219 - {0x2E44AE64840FD61D, 0xE2A0B5DC971F303A}, // 1e220 - {0x5CEAECFED289E5D2, 0x8DA471A9DE737E24}, // 1e221 - {0x7425A83E872C5F47, 0xB10D8E1456105DAD}, // 1e222 - {0xD12F124E28F77719, 0xDD50F1996B947518}, // 1e223 - {0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F}, // 1e224 - {0x636CC64D1001550B, 0xACE73CBFDC0BFB7B}, // 1e225 - {0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A}, // 1e226 - {0x65ACFAEC34810A71, 0x8714A775E3E95C78}, // 1e227 - {0x7F1839A741A14D0D, 0xA8D9D1535CE3B396}, // 1e228 - {0x1EDE48111209A050, 0xD31045A8341CA07C}, // 1e229 - {0x934AED0AAB460432, 0x83EA2B892091E44D}, // 1e230 - {0xF81DA84D5617853F, 0xA4E4B66B68B65D60}, // 1e231 - {0x36251260AB9D668E, 0xCE1DE40642E3F4B9}, // 1e232 - {0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3}, // 1e233 - {0xB24CF65B8612F81F, 0xA1075A24E4421730}, // 1e234 - {0xDEE033F26797B627, 0xC94930AE1D529CFC}, // 1e235 - {0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C}, // 1e236 - {0x8E1F289560EE864E, 0x9D412E0806E88AA5}, // 1e237 - {0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E}, // 1e238 - {0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2}, // 1e239 - {0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765}, // 1e240 - {0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F}, // 1e241 - {0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E}, // 1e242 - {0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9}, // 1e243 - {0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F}, // 1e244 - {0x84C86189216DC5ED, 0xEA53DF5FD18D5513}, // 1e245 - {0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C}, // 1e246 - {0x3FBC8C33221DC2A1, 0xB7118682DBB66A77}, // 1e247 - {0x0FABAF3FEAA5334A, 0xE4D5E82392A40515}, // 1e248 - {0x29CB4D87F2A7400E, 0x8F05B1163BA6832D}, // 1e249 - {0x743E20E9EF511012, 0xB2C71D5BCA9023F8}, // 1e250 - {0x914DA9246B255416, 0xDF78E4B2BD342CF6}, // 1e251 - {0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A}, // 1e252 - {0xA184AC2473B529B1, 0xAE9672ABA3D0C320}, // 1e253 - {0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8}, // 1e254 - {0x7E2FA67C7A658892, 0x8865899617FB1871}, // 1e255 - {0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D}, // 1e256 - {0x552A74227F3EA565, 0xD51EA6FA85785631}, // 1e257 - {0xD53A88958F87275F, 0x8533285C936B35DE}, // 1e258 - {0x8A892ABAF368F137, 0xA67FF273B8460356}, // 1e259 - {0x2D2B7569B0432D85, 0xD01FEF10A657842C}, // 1e260 - {0x9C3B29620E29FC73, 0x8213F56A67F6B29B}, // 1e261 - {0x8349F3BA91B47B8F, 0xA298F2C501F45F42}, // 1e262 - {0x241C70A936219A73, 0xCB3F2F7642717713}, // 1e263 - {0xED238CD383AA0110, 0xFE0EFB53D30DD4D7}, // 1e264 - {0xF4363804324A40AA, 0x9EC95D1463E8A506}, // 1e265 - {0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48}, // 1e266 - {0xDD94B7868E94050A, 0xF81AA16FDC1B81DA}, // 1e267 - {0xCA7CF2B4191C8326, 0x9B10A4E5E9913128}, // 1e268 - {0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72}, // 1e269 - {0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF}, // 1e270 - {0xD5BE0503E085D813, 0x976E41088617CA01}, // 1e271 - {0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82}, // 1e272 - {0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2}, // 1e273 - {0xCABB90E5C942B503, 0x93E1AB8252F33B45}, // 1e274 - {0x3D6A751F3B936243, 0xB8DA1662E7B00A17}, // 1e275 - {0x0CC512670A783AD4, 0xE7109BFBA19C0C9D}, // 1e276 - {0x27FB2B80668B24C5, 0x906A617D450187E2}, // 1e277 - {0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA}, // 1e278 - {0x5E7873F8A0396973, 0xE1A63853BBD26451}, // 1e279 - {0xDB0B487B6423E1E8, 0x8D07E33455637EB2}, // 1e280 - {0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F}, // 1e281 - {0x7641A140CC7810FB, 0xDC5C5301C56B75F7}, // 1e282 - {0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA}, // 1e283 - {0x546345FA9FBDCD44, 0xAC2820D9623BF429}, // 1e284 - {0xA97C177947AD4095, 0xD732290FBACAF133}, // 1e285 - {0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0}, // 1e286 - {0x5C68F256BFFF5A74, 0xA81F301449EE8C70}, // 1e287 - {0x73832EEC6FFF3111, 0xD226FC195C6A2F8C}, // 1e288 - {0xC831FD53C5FF7EAB, 0x83585D8FD9C25DB7}, // 1e289 - {0xBA3E7CA8B77F5E55, 0xA42E74F3D032F525}, // 1e290 - {0x28CE1BD2E55F35EB, 0xCD3A1230C43FB26F}, // 1e291 - {0x7980D163CF5B81B3, 0x80444B5E7AA7CF85}, // 1e292 - {0xD7E105BCC332621F, 0xA0555E361951C366}, // 1e293 - {0x8DD9472BF3FEFAA7, 0xC86AB5C39FA63440}, // 1e294 - {0xB14F98F6F0FEB951, 0xFA856334878FC150}, // 1e295 - {0x6ED1BF9A569F33D3, 0x9C935E00D4B9D8D2}, // 1e296 - {0x0A862F80EC4700C8, 0xC3B8358109E84F07}, // 1e297 - {0xCD27BB612758C0FA, 0xF4A642E14C6262C8}, // 1e298 - {0x8038D51CB897789C, 0x98E7E9CCCFBD7DBD}, // 1e299 - {0xE0470A63E6BD56C3, 0xBF21E44003ACDD2C}, // 1e300 - {0x1858CCFCE06CAC74, 0xEEEA5D5004981478}, // 1e301 - {0x0F37801E0C43EBC8, 0x95527A5202DF0CCB}, // 1e302 - {0xD30560258F54E6BA, 0xBAA718E68396CFFD}, // 1e303 - {0x47C6B82EF32A2069, 0xE950DF20247C83FD}, // 1e304 - {0x4CDC331D57FA5441, 0x91D28B7416CDD27E}, // 1e305 - {0xE0133FE4ADF8E952, 0xB6472E511C81471D}, // 1e306 - {0x58180FDDD97723A6, 0xE3D8F9E563A198E5}, // 1e307 - {0x570F09EAA7EA7648, 0x8E679C2F5E44FF8F}, // 1e308 - {0x2CD2CC6551E513DA, 0xB201833B35D63F73}, // 1e309 - {0xF8077F7EA65E58D1, 0xDE81E40A034BCF4F}, // 1e310 - {0xFB04AFAF27FAF782, 0x8B112E86420F6191}, // 1e311 - {0x79C5DB9AF1F9B563, 0xADD57A27D29339F6}, // 1e312 - {0x18375281AE7822BC, 0xD94AD8B1C7380874}, // 1e313 - {0x8F2293910D0B15B5, 0x87CEC76F1C830548}, // 1e314 - {0xB2EB3875504DDB22, 0xA9C2794AE3A3C69A}, // 1e315 - {0x5FA60692A46151EB, 0xD433179D9C8CB841}, // 1e316 - {0xDBC7C41BA6BCD333, 0x849FEEC281D7F328}, // 1e317 - {0x12B9B522906C0800, 0xA5C7EA73224DEFF3}, // 1e318 - {0xD768226B34870A00, 0xCF39E50FEAE16BEF}, // 1e319 - {0xE6A1158300D46640, 0x81842F29F2CCE375}, // 1e320 - {0x60495AE3C1097FD0, 0xA1E53AF46F801C53}, // 1e321 - {0x385BB19CB14BDFC4, 0xCA5E89B18B602368}, // 1e322 - {0x46729E03DD9ED7B5, 0xFCF62C1DEE382C42}, // 1e323 - {0x6C07A2C26A8346D1, 0x9E19DB92B4E31BA9}, // 1e324 - {0xC7098B7305241885, 0xC5A05277621BE293}, // 1e325 - {0xB8CBEE4FC66D1EA7, 0xF70867153AA2DB38}, // 1e326 - {0x737F74F1DC043328, 0x9A65406D44A5C903}, // 1e327 - {0x505F522E53053FF2, 0xC0FE908895CF3B44}, // 1e328 - {0x647726B9E7C68FEF, 0xF13E34AABB430A15}, // 1e329 - {0x5ECA783430DC19F5, 0x96C6E0EAB509E64D}, // 1e330 - {0xB67D16413D132072, 0xBC789925624C5FE0}, // 1e331 - {0xE41C5BD18C57E88F, 0xEB96BF6EBADF77D8}, // 1e332 - {0x8E91B962F7B6F159, 0x933E37A534CBAAE7}, // 1e333 - {0x723627BBB5A4ADB0, 0xB80DC58E81FE95A1}, // 1e334 - {0xCEC3B1AAA30DD91C, 0xE61136F2227E3B09}, // 1e335 - {0x213A4F0AA5E8A7B1, 0x8FCAC257558EE4E6}, // 1e336 - {0xA988E2CD4F62D19D, 0xB3BD72ED2AF29E1F}, // 1e337 - {0x93EB1B80A33B8605, 0xE0ACCFA875AF45A7}, // 1e338 - {0xBC72F130660533C3, 0x8C6C01C9498D8B88}, // 1e339 - {0xEB8FAD7C7F8680B4, 0xAF87023B9BF0EE6A}, // 1e340 - {0xA67398DB9F6820E1, 0xDB68C2CA82ED2A05}, // 1e341 - {0x88083F8943A1148C, 0x892179BE91D43A43}, // 1e342 - {0x6A0A4F6B948959B0, 0xAB69D82E364948D4}, // 1e343 - {0x848CE34679ABB01C, 0xD6444E39C3DB9B09}, // 1e344 - {0xF2D80E0C0C0B4E11, 0x85EAB0E41A6940E5}, // 1e345 - {0x6F8E118F0F0E2195, 0xA7655D1D2103911F}, // 1e346 - {0x4B7195F2D2D1A9FB, 0xD13EB46469447567}, // 1e347 -} diff --git a/examples/gno.land/p/demo/json/eisel_lemire/gno.mod b/examples/gno.land/p/demo/json/eisel_lemire/gno.mod deleted file mode 100644 index d6670de82e2..00000000000 --- a/examples/gno.land/p/demo/json/eisel_lemire/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/p/demo/json/eisel_lemire diff --git a/examples/gno.land/p/demo/json/encode.gno b/examples/gno.land/p/demo/json/encode.gno index be90d7aa73d..55828650e22 100644 --- a/examples/gno.land/p/demo/json/encode.gno +++ b/examples/gno.land/p/demo/json/encode.gno @@ -3,10 +3,8 @@ package json import ( "bytes" "errors" - "math" "strconv" - "gno.land/p/demo/json/ryu" "gno.land/p/demo/ufmt" ) @@ -44,17 +42,8 @@ func Marshal(node *Node) ([]byte, error) { return nil, err } - // ufmt does not support %g. by doing so, we need to check if the number is an integer - // after then, apply the correct format for each float and integer numbers. - if math.Mod(nVal, 1.0) == 0 { - // must convert float to integer. otherwise it will be overflowed. - num := ufmt.Sprintf("%d", int(nVal)) - buf.WriteString(num) - } else { - // use ryu algorithm to convert float to string - num := ryu.FormatFloat64(nVal) - buf.WriteString(num) - } + num := strconv.FormatFloat(nVal, 'f', -1, 64) + buf.WriteString(num) case String: sVal, err = node.GetString() diff --git a/examples/gno.land/p/demo/json/encode_test.gno b/examples/gno.land/p/demo/json/encode_test.gno index e8e53993b5c..831a9e0e0a2 100644 --- a/examples/gno.land/p/demo/json/encode_test.gno +++ b/examples/gno.land/p/demo/json/encode_test.gno @@ -37,10 +37,9 @@ func TestMarshal_Primitive(t *testing.T) { name: "42", node: NumberNode("", 42), }, - // TODO: fix output for not to use scientific notation { - name: "1.005e+02", - node: NumberNode("", 100.5), + name: "3.14", + node: NumberNode("", 3.14), }, { name: `[1,2,3]`, diff --git a/examples/gno.land/p/demo/json/errors.gno b/examples/gno.land/p/demo/json/errors.gno new file mode 100644 index 00000000000..e0836dccdff --- /dev/null +++ b/examples/gno.land/p/demo/json/errors.gno @@ -0,0 +1,34 @@ +package json + +import "errors" + +var ( + errNilNode = errors.New("node is nil") + errNotArrayNode = errors.New("node is not array") + errNotBoolNode = errors.New("node is not boolean") + errNotNullNode = errors.New("node is not null") + errNotNumberNode = errors.New("node is not number") + errNotObjectNode = errors.New("node is not object") + errNotStringNode = errors.New("node is not string") + errInvalidToken = errors.New("invalid token") + errIndexNotFound = errors.New("index not found") + errInvalidAppend = errors.New("can't append value to non-appendable node") + errInvalidAppendCycle = errors.New("appending value to itself or its children or parents will cause a cycle") + errInvalidEscapeSequence = errors.New("invalid escape sequence") + errInvalidStringValue = errors.New("invalid string value") + errEmptyBooleanNode = errors.New("boolean node is empty") + errEmptyStringNode = errors.New("string node is empty") + errKeyRequired = errors.New("key is required for object") + errUnmatchedParenthesis = errors.New("mismatched bracket or parenthesis") + errUnmatchedQuotePath = errors.New("unmatched quote in path") +) + +var ( + errInvalidStringInput = errors.New("invalid string input") + errMalformedBooleanValue = errors.New("malformed boolean value") + errEmptyByteSlice = errors.New("empty byte slice") + errInvalidExponentValue = errors.New("invalid exponent value") + errNonDigitCharacters = errors.New("non-digit characters found") + errNumericRangeExceeded = errors.New("numeric value exceeds the range limit") + errMultipleDecimalPoints = errors.New("multiple decimal points found") +) diff --git a/examples/gno.land/p/demo/json/escape.gno b/examples/gno.land/p/demo/json/escape.gno index 5a834068127..ee3e4a79855 100644 --- a/examples/gno.land/p/demo/json/escape.gno +++ b/examples/gno.land/p/demo/json/escape.gno @@ -1,8 +1,6 @@ package json import ( - "bytes" - "errors" "unicode/utf8" ) @@ -13,6 +11,9 @@ const ( surrogateEnd = 0xDFFF basicMultilingualPlaneOffset = 0xFFFF badHex = -1 + + singleUnicodeEscapeLen = 6 + surrogatePairLen = 12 ) var hexLookupTable = [256]int{ @@ -42,48 +43,32 @@ func h2i(c byte) int { // // it returns the processed slice and any error encountered during the Unescape operation. func Unescape(input, output []byte) ([]byte, error) { - // find the index of the first backslash in the input slice. - firstBackslash := bytes.IndexByte(input, backSlash) - if firstBackslash == -1 { - return input, nil - } - - // ensure the output slice has enough capacity to hold the result. + // ensure the output slice has enough capacity to hold the input slice. inputLen := len(input) if cap(output) < inputLen { output = make([]byte, inputLen) } - output = output[:inputLen] - copy(output, input[:firstBackslash]) - - input = input[firstBackslash:] - buf := output[firstBackslash:] - - for len(input) > 0 { - inLen, bufLen, err := processEscapedUTF8(input, buf) - if err != nil { - return nil, err - } - - input = input[inLen:] // the number of bytes consumed in the input - buf = buf[bufLen:] // the number of bytes written to buf + inPos, outPos := 0, 0 - // find the next backslash in the remaining input - nextBackslash := bytes.IndexByte(input, backSlash) - if nextBackslash == -1 { - copy(buf, input) - buf = buf[len(input):] - break + for inPos < len(input) { + c := input[inPos] + if c != backSlash { + output[outPos] = c + inPos++ + outPos++ + } else { + // process escape sequence + inLen, outLen, err := processEscapedUTF8(input[inPos:], output[outPos:]) + if err != nil { + return nil, err + } + inPos += inLen + outPos += outLen } - - copy(buf, input[:nextBackslash]) - - input = input[nextBackslash:] - buf = buf[nextBackslash:] } - return output[:len(output)-len(buf)], nil + return output[:outPos], nil } // isSurrogatePair returns true if the rune is a surrogate pair. @@ -94,6 +79,16 @@ func isSurrogatePair(r rune) bool { return highSurrogateOffset <= r && r <= surrogateEnd } +// isHighSurrogate checks if the rune is a high surrogate (U+D800 to U+DBFF). +func isHighSurrogate(r rune) bool { + return r >= highSurrogateOffset && r <= 0xDBFF +} + +// isLowSurrogate checks if the rune is a low surrogate (U+DC00 to U+DFFF). +func isLowSurrogate(r rune) bool { + return r >= lowSurrogateOffset && r <= surrogateEnd +} + // combineSurrogates reconstruct the original unicode code points in the // supplemental plane by combinin the high and low surrogate. // @@ -122,28 +117,41 @@ func decodeSingleUnicodeEscape(b []byte) (rune, bool) { } // decodeUnicodeEscape decodes a Unicode escape sequence from a byte slice. +// It handles both single Unicode escape sequences and surrogate pairs. func decodeUnicodeEscape(b []byte) (rune, int) { + // decode the first Unicode escape sequence. r, ok := decodeSingleUnicodeEscape(b) if !ok { return utf8.RuneError, -1 } - // determine valid unicode escapes within the BMP + // if the rune is within the BMP and not a surrogate, return it if r <= basicMultilingualPlaneOffset && !isSurrogatePair(r) { return r, 6 } - // Decode the following escape sequence to verify a UTF-16 susergate pair. - r2, ok := decodeSingleUnicodeEscape(b[6:]) - if !ok { + if !isHighSurrogate(r) { + // invalid surrogate pair. return utf8.RuneError, -1 } - if r2 < lowSurrogateOffset { + // if the rune is a high surrogate, need to decode the next escape sequence. + + // ensure there are enough bytes for the next escape sequence. + if len(b) < surrogatePairLen { return utf8.RuneError, -1 } - - return combineSurrogates(r, r2), 12 + // decode the second Unicode escape sequence. + r2, ok := decodeSingleUnicodeEscape(b[singleUnicodeEscapeLen:]) + if !ok { + return utf8.RuneError, -1 + } + // check if the second rune is a low surrogate. + if isLowSurrogate(r2) { + combined := combineSurrogates(r, r2) + return combined, surrogatePairLen + } + return utf8.RuneError, -1 } var escapeByteSet = [256]byte{ @@ -165,7 +173,6 @@ func Unquote(s []byte, border byte) (string, bool) { } // unquoteBytes takes a byte slice and unquotes it by removing -// TODO: consider to move this function to the strconv package. func unquoteBytes(s []byte, border byte) ([]byte, bool) { if len(s) < 2 || s[0] != border || s[len(s)-1] != border { return nil, false @@ -259,21 +266,12 @@ func unquoteBytes(s []byte, border byte) ([]byte, bool) { return b[:w], true } -// processEscapedUTF8 processes the escape sequence in the given byte slice and -// and converts them to UTF-8 characters. The function returns the length of the processed input and output. -// -// The input 'in' must contain the escape sequence to be processed, -// and 'out' provides a space to store the converted characters. -// -// The function returns (input length, output length) if the escape sequence is correct. -// Unicode escape sequences (e.g. \uXXXX) are decoded to UTF-8, other default escape sequences are -// converted to their corresponding special characters (e.g. \n -> newline). -// -// If the escape sequence is invalid, or if 'in' does not completely enclose the escape sequence, -// function returns (-1, -1) to indicate an error. +// processEscapedUTF8 converts escape sequences to UTF-8 characters. +// It decodes Unicode escape sequences (\uXXXX) to UTF-8 and +// converts standard escape sequences (e.g., \n) to their corresponding special characters. func processEscapedUTF8(in, out []byte) (int, int, error) { if len(in) < 2 || in[0] != backSlash { - return -1, -1, errors.New("invalid escape sequence") + return -1, -1, errInvalidEscapeSequence } escapeSeqLen := 2 @@ -282,7 +280,7 @@ func processEscapedUTF8(in, out []byte) (int, int, error) { if escapeChar != 'u' { val := escapeByteSet[escapeChar] if val == 0 { - return -1, -1, errors.New("invalid escape sequence") + return -1, -1, errInvalidEscapeSequence } out[0] = val @@ -291,7 +289,7 @@ func processEscapedUTF8(in, out []byte) (int, int, error) { r, size := decodeUnicodeEscape(in) if size == -1 { - return -1, -1, errors.New("invalid escape sequence") + return -1, -1, errInvalidEscapeSequence } outLen := utf8.EncodeRune(out, r) diff --git a/examples/gno.land/p/demo/json/escape_test.gno b/examples/gno.land/p/demo/json/escape_test.gno index 40c118d93ce..0e2e696e83c 100644 --- a/examples/gno.land/p/demo/json/escape_test.gno +++ b/examples/gno.land/p/demo/json/escape_test.gno @@ -103,24 +103,25 @@ func TestDecodeSingleUnicodeEscape(t *testing.T) { } func TestDecodeUnicodeEscape(t *testing.T) { - testCases := []struct { - input string + tests := []struct { + input []byte expected rune size int }{ - {"\\u0041", 'A', 6}, - {"\\u03B1", 'α', 6}, - {"\\u1F600", 0x1F60, 6}, - {"\\uD830\\uDE03", 0x1C203, 12}, - {"\\uD800\\uDC00", 0x00010000, 12}, - - {"\\u004", utf8.RuneError, -1}, - {"\\uXYZW", utf8.RuneError, -1}, - {"\\uD83D\\u0041", utf8.RuneError, -1}, + {[]byte(`\u0041`), 'A', 6}, + {[]byte(`\uD83D\uDE00`), 0x1F600, 12}, // 😀 + {[]byte(`\uD834\uDD1E`), 0x1D11E, 12}, // 𝄞 + {[]byte(`\uFFFF`), '\uFFFF', 6}, + {[]byte(`\uXYZW`), utf8.RuneError, -1}, + {[]byte(`\uD800`), utf8.RuneError, -1}, // single high surrogate + {[]byte(`\uDC00`), utf8.RuneError, -1}, // single low surrogate + {[]byte(`\uD800\uDC00`), 0x10000, 12}, // First code point above U+FFFF + {[]byte(`\uDBFF\uDFFF`), 0x10FFFF, 12}, // Maximum code point + {[]byte(`\uD83D\u0041`), utf8.RuneError, -1}, // invalid surrogate pair } - for _, tc := range testCases { - r, size := decodeUnicodeEscape([]byte(tc.input)) + for _, tc := range tests { + r, size := decodeUnicodeEscape(tc.input) if r != tc.expected || size != tc.size { t.Errorf("decodeUnicodeEscape(%q) = (%U, %d); want (%U, %d)", tc.input, r, size, tc.expected, tc.size) } @@ -128,7 +129,7 @@ func TestDecodeUnicodeEscape(t *testing.T) { } func TestUnescapeToUTF8(t *testing.T) { - testCases := []struct { + tests := []struct { input []byte expectedIn int expectedOut int @@ -150,7 +151,7 @@ func TestUnescapeToUTF8(t *testing.T) { {[]byte(`\uD83D\u0041`), -1, -1, true}, // invalid unicode escape sequence } - for _, tc := range testCases { + for _, tc := range tests { input := make([]byte, len(tc.input)) copy(input, tc.input) output := make([]byte, utf8.UTFMax) @@ -166,23 +167,32 @@ func TestUnescapeToUTF8(t *testing.T) { } func TestUnescape(t *testing.T) { - testCases := []struct { + tests := []struct { name string input []byte expected []byte + isError bool }{ - {"NoEscape", []byte("hello world"), []byte("hello world")}, - {"SingleEscape", []byte("hello\\nworld"), []byte("hello\nworld")}, - {"MultipleEscapes", []byte("line1\\nline2\\r\\nline3"), []byte("line1\nline2\r\nline3")}, - {"UnicodeEscape", []byte("snowman:\\u2603"), []byte("snowman:\u2603")}, - {"Complex", []byte("tc\\n\\u2603\\r\\nend"), []byte("tc\n\u2603\r\nend")}, + {"NoEscape", []byte("hello world"), []byte("hello world"), false}, + {"SingleEscape", []byte("hello\\nworld"), []byte("hello\nworld"), false}, + {"MultipleEscapes", []byte("line1\\nline2\\r\\nline3"), []byte("line1\nline2\r\nline3"), false}, + {"UnicodeEscape", []byte("snowman:\\u2603"), []byte("snowman:\u2603"), false}, + {"SurrogatePair", []byte("emoji:\\uD83D\\uDE00"), []byte("emoji:😀"), false}, + {"InvalidEscape", []byte("hello\\xworld"), nil, true}, + {"IncompleteUnicode", []byte("incomplete:\\u123"), nil, true}, + {"InvalidSurrogatePair", []byte("invalid:\\uD83D\\u0041"), nil, true}, } - for _, tc := range testCases { + for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - output, _ := Unescape(tc.input, make([]byte, len(tc.input)+10)) - if !bytes.Equal(output, tc.expected) { - t.Errorf("unescape(%q) = %q; want %q", tc.input, output, tc.expected) + output := make([]byte, len(tc.input)*2) // Allocate extra space for possible expansion + result, err := Unescape(tc.input, output) + if (err != nil) != tc.isError { + t.Errorf("Unescape(%q) error = %v; want error = %v", tc.input, err, tc.isError) + } + + if !tc.isError && !bytes.Equal(result, tc.expected) { + t.Errorf("Unescape(%q) = %q; want %q", tc.input, result, tc.expected) } }) } @@ -206,6 +216,7 @@ func TestUnquoteBytes(t *testing.T) { {[]byte("\"\\u0041\""), '"', []byte("A"), true}, {[]byte(`"Hello, 世界"`), '"', []byte("Hello, 世界"), true}, {[]byte(`"Hello, \x80"`), '"', nil, false}, + {[]byte(`"invalid surrogate: \uD83D\u0041"`), '"', nil, false}, } for _, tc := range tests { diff --git a/examples/gno.land/p/demo/json/gno.mod b/examples/gno.land/p/demo/json/gno.mod index 8a380644acc..ef794458c56 100644 --- a/examples/gno.land/p/demo/json/gno.mod +++ b/examples/gno.land/p/demo/json/gno.mod @@ -1,7 +1,3 @@ module gno.land/p/demo/json -require ( - gno.land/p/demo/json/eisel_lemire v0.0.0-latest - gno.land/p/demo/json/ryu v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest -) +require gno.land/p/demo/ufmt v0.0.0-latest diff --git a/examples/gno.land/p/demo/json/indent.gno b/examples/gno.land/p/demo/json/indent.gno index cdcfd4524ee..cdf9d5e976f 100644 --- a/examples/gno.land/p/demo/json/indent.gno +++ b/examples/gno.land/p/demo/json/indent.gno @@ -9,21 +9,7 @@ import ( // A factor no higher than 2 ensures that wasted space never exceeds 50%. const indentGrowthFactor = 2 -// IndentJSON takes a JSON byte slice and a string for indentation, -// then formats the JSON according to the specified indent string. -// This function applies indentation rules as follows: -// -// 1. For top-level arrays and objects, no additional indentation is applied. -// -// 2. For nested structures like arrays within arrays or objects, indentation increases. -// -// 3. Indentation is applied after opening brackets ('[' or '{') and before closing brackets (']' or '}'). -// -// 4. Commas and colons are handled appropriately to maintain valid JSON format. -// -// 5. Nested arrays within objects or arrays receive new lines and indentation based on their depth level. -// -// The function returns the formatted JSON as a byte slice and an error if any issues occurred during formatting. +// IndentJSON formats the JSON data with the specified indentation. func Indent(data []byte, indent string) ([]byte, error) { var ( out bytes.Buffer diff --git a/examples/gno.land/p/demo/json/node.gno b/examples/gno.land/p/demo/json/node.gno index 1e71a101e62..c917150bc3d 100644 --- a/examples/gno.land/p/demo/json/node.gno +++ b/examples/gno.land/p/demo/json/node.gno @@ -44,7 +44,7 @@ func NewNode(prev *Node, b *buffer, typ ValueType, key **string) (*Node, error) prev.next[strconv.Itoa(size)] = curr } else if prev.IsObject() { if key == nil { - return nil, errors.New("key is required for object") + return nil, errKeyRequired } prev.next[**key] = curr @@ -88,7 +88,7 @@ func (n *Node) HasKey(key string) bool { // GetKey returns the value of the given key from the current object node. func (n *Node) GetKey(key string) (*Node, error) { if n == nil { - return nil, errors.New("node is nil") + return nil, errNilNode } if n.Type() != Object { @@ -174,7 +174,7 @@ func (n *Node) Value() (value interface{}, err error) { return nil, nil case Number: - value, err = ParseFloatLiteral(n.source()) + value, err = strconv.ParseFloat(string(n.source()), 64) if err != nil { return nil, err } @@ -185,14 +185,14 @@ func (n *Node) Value() (value interface{}, err error) { var ok bool value, ok = Unquote(n.source(), doubleQuote) if !ok { - return "", errors.New("invalid string value") + return "", errInvalidStringValue } n.value = value case Boolean: if len(n.source()) == 0 { - return nil, errors.New("empty boolean value") + return nil, errEmptyBooleanNode } b := n.source()[0] @@ -319,11 +319,11 @@ func (n *Node) MustIndex(expectIdx int) *Node { // if the index is negative, it returns the index is from the end of the array. func (n *Node) GetIndex(idx int) (*Node, error) { if n == nil { - return nil, errors.New("node is nil") + return nil, errNilNode } if !n.IsArray() { - return nil, errors.New("node is not array") + return nil, errNotArrayNode } if idx > n.Size() { @@ -336,7 +336,7 @@ func (n *Node) GetIndex(idx int) (*Node, error) { child, ok := n.next[strconv.Itoa(idx)] if !ok { - return nil, errors.New("index not found") + return nil, errIndexNotFound } return child, nil @@ -556,11 +556,11 @@ func (n *Node) root() *Node { // } func (n *Node) GetNull() (interface{}, error) { if n == nil { - return nil, errors.New("node is nil") + return nil, errNilNode } if !n.IsNull() { - return nil, errors.New("node is not null") + return nil, errNotNullNode } return nil, nil @@ -590,11 +590,11 @@ func (n *Node) MustNull() interface{} { // println(val) // 10.5 func (n *Node) GetNumeric() (float64, error) { if n == nil { - return 0, errors.New("node is nil") + return 0, errNilNode } if n.nodeType != Number { - return 0, errors.New("node is not number") + return 0, errNotNumberNode } val, err := n.Value() @@ -604,7 +604,7 @@ func (n *Node) GetNumeric() (float64, error) { v, ok := val.(float64) if !ok { - return 0, errors.New("node is not number") + return 0, errNotNumberNode } return v, nil @@ -639,11 +639,11 @@ func (n *Node) MustNumeric() float64 { // println(str) // "foo" func (n *Node) GetString() (string, error) { if n == nil { - return "", errors.New("string node is empty") + return "", errEmptyStringNode } if !n.IsString() { - return "", errors.New("node type is not string") + return "", errNotStringNode } val, err := n.Value() @@ -653,7 +653,7 @@ func (n *Node) GetString() (string, error) { v, ok := val.(string) if !ok { - return "", errors.New("node is not string") + return "", errNotStringNode } return v, nil @@ -683,11 +683,11 @@ func (n *Node) MustString() string { // println(val) // true func (n *Node) GetBool() (bool, error) { if n == nil { - return false, errors.New("node is nil") + return false, errNilNode } if n.nodeType != Boolean { - return false, errors.New("node is not boolean") + return false, errNotBoolNode } val, err := n.Value() @@ -697,7 +697,7 @@ func (n *Node) GetBool() (bool, error) { v, ok := val.(bool) if !ok { - return false, errors.New("node is not boolean") + return false, errNotBoolNode } return v, nil @@ -732,11 +732,11 @@ func (n *Node) MustBool() bool { // result: "foo", 1 func (n *Node) GetArray() ([]*Node, error) { if n == nil { - return nil, errors.New("node is nil") + return nil, errNilNode } if n.nodeType != Array { - return nil, errors.New("node is not array") + return nil, errNotArrayNode } val, err := n.Value() @@ -746,7 +746,7 @@ func (n *Node) GetArray() ([]*Node, error) { v, ok := val.([]*Node) if !ok { - return nil, errors.New("node is not array") + return nil, errNotArrayNode } return v, nil @@ -788,7 +788,7 @@ func (n *Node) MustArray() []*Node { // result: ["bar", "baz", 1, "foo"] func (n *Node) AppendArray(value ...*Node) error { if !n.IsArray() { - return errors.New("can't append value to non-array node") + return errInvalidAppend } for _, val := range value { @@ -836,11 +836,11 @@ func (n *Node) ArrayEach(callback func(i int, target *Node)) { // result: map[string]*Node{"key": StringNode("key", "value")} func (n *Node) GetObject() (map[string]*Node, error) { if n == nil { - return nil, errors.New("node is nil") + return nil, errNilNode } if !n.IsObject() { - return nil, errors.New("node is not object") + return nil, errNotObjectNode } val, err := n.Value() @@ -850,7 +850,7 @@ func (n *Node) GetObject() (map[string]*Node, error) { v, ok := val.(map[string]*Node) if !ok { - return nil, errors.New("node is not object") + return nil, errNotObjectNode } return v, nil @@ -873,7 +873,7 @@ func (n *Node) MustObject() map[string]*Node { // If the current node is not object type, it returns an error. func (n *Node) AppendObject(key string, value *Node) error { if !n.IsObject() { - return errors.New("can't append value to non-object node") + return errInvalidAppend } if err := n.append(&key, value); err != nil { @@ -1003,7 +1003,7 @@ func (n *Node) dropIndex(idx int) { // append is a helper function to append the given value to the current container type node. func (n *Node) append(key *string, val *Node) error { if n.isSameOrParentNode(val) { - return errors.New("can't append same or parent node") + return errInvalidAppendCycle } if val.prev != nil { diff --git a/examples/gno.land/p/demo/json/parser.gno b/examples/gno.land/p/demo/json/parser.gno index 9a2c3a8c817..bae06cb3789 100644 --- a/examples/gno.land/p/demo/json/parser.gno +++ b/examples/gno.land/p/demo/json/parser.gno @@ -2,27 +2,22 @@ package json import ( "bytes" - "errors" - "strconv" - - el "gno.land/p/demo/json/eisel_lemire" ) const ( - absMinInt64 = 1 << 63 - maxInt64 = absMinInt64 - 1 - maxUint64 = 1<<64 - 1 + unescapeStackBufSize = 64 + absMinInt64 = 1 << 63 + maxInt64 = absMinInt64 - 1 + maxUint64 = 1<<64 - 1 ) -const unescapeStackBufSize = 64 - // PaseStringLiteral parses a string from the given byte slice. func ParseStringLiteral(data []byte) (string, error) { var buf [unescapeStackBufSize]byte bf, err := Unescape(data, buf[:]) if err != nil { - return "", errors.New("invalid string input found while parsing string value") + return "", errInvalidStringInput } return string(bf), nil @@ -36,150 +31,6 @@ func ParseBoolLiteral(data []byte) (bool, error) { case bytes.Equal(data, falseLiteral): return false, nil default: - return false, errors.New("JSON Error: malformed boolean value found while parsing boolean value") - } -} - -// PaseFloatLiteral parses a float64 from the given byte slice. -// -// It utilizes double-precision (64-bit) floating-point format as defined -// by the IEEE 754 standard, providing a decimal precision of approximately 15 digits. -func ParseFloatLiteral(bytes []byte) (float64, error) { - if len(bytes) == 0 { - return -1, errors.New("JSON Error: empty byte slice found while parsing float value") - } - - neg, bytes := trimNegativeSign(bytes) - - var exponentPart []byte - for i, c := range bytes { - if lower(c) == 'e' { - exponentPart = bytes[i+1:] - bytes = bytes[:i] - break - } - } - - man, exp10, err := extractMantissaAndExp10(bytes) - if err != nil { - return -1, err - } - - if len(exponentPart) > 0 { - exp, err := strconv.Atoi(string(exponentPart)) - if err != nil { - return -1, errors.New("JSON Error: invalid exponent value found while parsing float value") - } - exp10 += exp - } - - // for fast float64 conversion - f, success := el.EiselLemire64(man, exp10, neg) - if !success { - return 0, nil - } - - return f, nil -} - -func ParseIntLiteral(bytes []byte) (int64, error) { - if len(bytes) == 0 { - return 0, errors.New("JSON Error: empty byte slice found while parsing integer value") - } - - neg, bytes := trimNegativeSign(bytes) - - var n uint64 = 0 - for _, c := range bytes { - if notDigit(c) { - return 0, errors.New("JSON Error: non-digit characters found while parsing integer value") - } - - if n > maxUint64/10 { - return 0, errors.New("JSON Error: numeric value exceeds the range limit") - } - - n *= 10 - - n1 := n + uint64(c-'0') - if n1 < n { - return 0, errors.New("JSON Error: numeric value exceeds the range limit") - } - - n = n1 - } - - if n > maxInt64 { - if neg && n == absMinInt64 { - return -absMinInt64, nil - } - - return 0, errors.New("JSON Error: numeric value exceeds the range limit") + return false, errMalformedBooleanValue } - - if neg { - return -int64(n), nil - } - - return int64(n), nil -} - -// extractMantissaAndExp10 parses a byte slice representing a decimal number and extracts the mantissa and the exponent of its base-10 representation. -// It iterates through the bytes, constructing the mantissa by treating each byte as a digit. -// If a decimal point is encountered, the function keeps track of the position of the decimal point to calculate the exponent. -// The function ensures that: -// - The number contains at most one decimal point. -// - All characters in the byte slice are digits or a single decimal point. -// - The resulting mantissa does not overflow a uint64. -func extractMantissaAndExp10(bytes []byte) (uint64, int, error) { - var ( - man uint64 - exp10 int - decimalFound bool - ) - - for _, c := range bytes { - if c == dot { - if decimalFound { - return 0, 0, errors.New("JSON Error: multiple decimal points found while parsing float value") - } - decimalFound = true - continue - } - - if notDigit(c) { - return 0, 0, errors.New("JSON Error: non-digit characters found while parsing integer value") - } - - digit := uint64(c - '0') - - if man > (maxUint64-digit)/10 { - return 0, 0, errors.New("JSON Error: numeric value exceeds the range limit") - } - - man = man*10 + digit - - if decimalFound { - exp10-- - } - } - - return man, exp10, nil -} - -func trimNegativeSign(bytes []byte) (bool, []byte) { - if bytes[0] == minus { - return true, bytes[1:] - } - - return false, bytes -} - -func notDigit(c byte) bool { - return (c & 0xF0) != 0x30 -} - -// lower converts a byte to lower case if it is an uppercase letter. -func lower(c byte) byte { - return c | 0x20 } diff --git a/examples/gno.land/p/demo/json/parser_test.gno b/examples/gno.land/p/demo/json/parser_test.gno index 078aa048a61..a05e313f67b 100644 --- a/examples/gno.land/p/demo/json/parser_test.gno +++ b/examples/gno.land/p/demo/json/parser_test.gno @@ -64,125 +64,3 @@ func TestParseBoolLiteral(t *testing.T) { } } } - -func TestParseFloatLiteral(t *testing.T) { - tests := []struct { - input string - expected float64 - }{ - {"123", 123}, - {"-123", -123}, - {"123.456", 123.456}, - {"-123.456", -123.456}, - {"12345678.1234567890", 12345678.1234567890}, - {"-12345678.09123456789", -12345678.09123456789}, - {"0.123", 0.123}, - {"-0.123", -0.123}, - {"", -1}, - {"abc", -1}, - {"123.45.6", -1}, - {"999999999999999999999", -1}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - got, _ := ParseFloatLiteral([]byte(tt.input)) - if got != tt.expected { - t.Errorf("ParseFloatLiteral(%s): got %v, want %v", tt.input, got, tt.expected) - } - }) - } -} - -func TestParseFloatWithScientificNotation(t *testing.T) { - tests := []struct { - input string - expected float64 - }{ - {"1e6", 1000000}, - {"1E6", 1000000}, - {"1.23e10", 1.23e10}, - {"1.23E10", 1.23e10}, - {"-1.23e10", -1.23e10}, - {"-1.23E10", -1.23e10}, - {"2.45e-8", 2.45e-8}, - {"2.45E-8", 2.45e-8}, - {"-2.45e-8", -2.45e-8}, - {"-2.45E-8", -2.45e-8}, - {"5e0", 5}, - {"-5e0", -5}, - {"5E+0", 5}, - {"5e+1", 50}, - {"1e-1", 0.1}, - {"1E-1", 0.1}, - {"-1e-1", -0.1}, - {"-1E-1", -0.1}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - got, err := ParseFloatLiteral([]byte(tt.input)) - if got != tt.expected { - t.Errorf("ParseFloatLiteral(%s): got %v, want %v", tt.input, got, tt.expected) - } - - if err != nil { - t.Errorf("ParseFloatLiteral(%s): got error %v", tt.input, err) - } - }) - } -} - -func TestParseFloat_May_Interoperability_Problem(t *testing.T) { - tests := []struct { - input string - shouldErr bool - }{ - {"3.141592653589793238462643383279", true}, - {"1E400", false}, // TODO: should error - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - _, err := ParseFloatLiteral([]byte(tt.input)) - if tt.shouldErr && err == nil { - t.Errorf("ParseFloatLiteral(%s): expected error, but not error", tt.input) - } - }) - } -} - -func TestParseIntLiteral(t *testing.T) { - tests := []struct { - input string - expected int64 - }{ - {"0", 0}, - {"1", 1}, - {"-1", -1}, - {"12345", 12345}, - {"-12345", -12345}, - {"9223372036854775807", 9223372036854775807}, - {"-9223372036854775808", -9223372036854775808}, - {"-92233720368547758081", 0}, - {"18446744073709551616", 0}, - {"9223372036854775808", 0}, - {"-9223372036854775809", 0}, - {"", 0}, - {"abc", 0}, - {"12345x", 0}, - {"123e5", 0}, - {"9223372036854775807x", 0}, - {"27670116110564327410", 0}, - {"-27670116110564327410", 0}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - got, _ := ParseIntLiteral([]byte(tt.input)) - if got != tt.expected { - t.Errorf("ParseIntLiteral(%s): got %v, want %v", tt.input, got, tt.expected) - } - }) - } -} diff --git a/examples/gno.land/p/demo/json/ryu/License b/examples/gno.land/p/demo/json/ryu/License deleted file mode 100644 index 55beeadce54..00000000000 --- a/examples/gno.land/p/demo/json/ryu/License +++ /dev/null @@ -1,21 +0,0 @@ -# Apache License - -Copyright 2018 Ulf Adams -Modifications copyright 2019 Caleb Spare - -The contents of this file may be used under the terms of the Apache License, -Version 2.0. - - (See accompanying file LICENSE or copy at - ) - -Unless required by applicable law or agreed to in writing, this software -is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. - -The code in this file is part of a Go translation of the C code originally written by -Ulf Adams, which can be found at . The original source -code is licensed under the Apache License 2.0. This code is a derivative work thereof, -adapted and modified to meet the specifications of the Gno language project. - -Please note that the modifications are also under the Apache License 2.0 unless otherwise specified. diff --git a/examples/gno.land/p/demo/json/ryu/floatconv.gno b/examples/gno.land/p/demo/json/ryu/floatconv.gno deleted file mode 100644 index 617141d2734..00000000000 --- a/examples/gno.land/p/demo/json/ryu/floatconv.gno +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2018 Ulf Adams -// Modifications copyright 2019 Caleb Spare -// -// The contents of this file may be used under the terms of the Apache License, -// Version 2.0. -// -// (See accompanying file LICENSE or copy at -// http://www.apache.org/licenses/LICENSE-2.0) -// -// Unless required by applicable law or agreed to in writing, this software -// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. -// -// The code in this file is part of a Go translation of the C code originally written by -// Ulf Adams, which can be found at https://github.com/ulfjack/ryu. The original source -// code is licensed under the Apache License 2.0. This code is a derivative work thereof, -// adapted and modified to meet the specifications of the Gno language project. -// -// original Go implementation can be found at https://github.com/cespare/ryu. -// -// Please note that the modifications are also under the Apache License 2.0 unless -// otherwise specified. - -// Package ryu implements the Ryu algorithm for quickly converting floating -// point numbers into strings. -package ryu - -import ( - "math" -) - -const ( - mantBits32 = 23 - expBits32 = 8 - bias32 = 127 - - mantBits64 = 52 - expBits64 = 11 - bias64 = 1023 -) - -// FormatFloat64 converts a 64-bit floating point number f to a string. -// It behaves like strconv.FormatFloat(f, 'e', -1, 64). -func FormatFloat64(f float64) string { - b := make([]byte, 0, 24) - b = AppendFloat64(b, f) - return string(b) -} - -// AppendFloat64 appends the string form of the 64-bit floating point number f, -// as generated by FormatFloat64, to b and returns the extended buffer. -func AppendFloat64(b []byte, f float64) []byte { - // Step 1: Decode the floating-point number. - // Unify normalized and subnormal cases. - u := math.Float64bits(f) - neg := u>>(mantBits64+expBits64) != 0 - mant := u & (uint64(1)<> mantBits64) & (uint64(1)<= 0, "e >= 0") - assert(e <= 1650, "e <= 1650") - return (uint32(e) * 78913) >> 18 -} - -// log10Pow5 returns floor(log_10(5^e)). -func log10Pow5(e int32) uint32 { - // The first value this approximation fails for is 5^2621 - // which is just greater than 10^1832. - assert(e >= 0, "e >= 0") - assert(e <= 2620, "e <= 2620") - return (uint32(e) * 732923) >> 20 -} - -// pow5Bits returns ceil(log_2(5^e)), or else 1 if e==0. -func pow5Bits(e int32) int32 { - // This approximation works up to the point that the multiplication - // overflows at e = 3529. If the multiplication were done in 64 bits, - // it would fail at 5^4004 which is just greater than 2^9297. - assert(e >= 0, "e >= 0") - assert(e <= 3528, "e <= 3528") - return int32((uint32(e)*1217359)>>19 + 1) -} diff --git a/examples/gno.land/p/demo/json/ryu/floatconv_test.gno b/examples/gno.land/p/demo/json/ryu/floatconv_test.gno deleted file mode 100644 index 7f01d4034f7..00000000000 --- a/examples/gno.land/p/demo/json/ryu/floatconv_test.gno +++ /dev/null @@ -1,33 +0,0 @@ -package ryu - -import ( - "math" - "testing" -) - -func TestFormatFloat64(t *testing.T) { - tests := []struct { - name string - value float64 - expected string - }{ - {"positive infinity", math.Inf(1), "+Inf"}, - {"negative infinity", math.Inf(-1), "-Inf"}, - {"NaN", math.NaN(), "NaN"}, - {"zero", 0.0, "0e+00"}, - {"negative zero", -0.0, "0e+00"}, - {"positive number", 3.14159, "3.14159e+00"}, - {"negative number", -2.71828, "-2.71828e+00"}, - {"very small number", 1.23e-20, "1.23e-20"}, - {"very large number", 1.23e+20, "1.23e+20"}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - result := FormatFloat64(test.value) - if result != test.expected { - t.Errorf("FormatFloat64(%v) = %q, expected %q", test.value, result, test.expected) - } - }) - } -} diff --git a/examples/gno.land/p/demo/json/ryu/gno.mod b/examples/gno.land/p/demo/json/ryu/gno.mod deleted file mode 100644 index 86a1988b052..00000000000 --- a/examples/gno.land/p/demo/json/ryu/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/p/demo/json/ryu diff --git a/examples/gno.land/p/demo/json/ryu/ryu64.gno b/examples/gno.land/p/demo/json/ryu/ryu64.gno deleted file mode 100644 index 249e3d0f526..00000000000 --- a/examples/gno.land/p/demo/json/ryu/ryu64.gno +++ /dev/null @@ -1,344 +0,0 @@ -package ryu - -import ( - "math/bits" -) - -type uint128 struct { - lo uint64 - hi uint64 -} - -// dec64 is a floating decimal type representing m * 10^e. -type dec64 struct { - m uint64 - e int32 -} - -func (d dec64) append(b []byte, neg bool) []byte { - // Step 5: Print the decimal representation. - if neg { - b = append(b, '-') - } - - out := d.m - outLen := decimalLen64(out) - bufLen := outLen - if bufLen > 1 { - bufLen++ // extra space for '.' - } - - // Print the decimal digits. - n := len(b) - if cap(b)-len(b) >= bufLen { - // Avoid function call in the common case. - b = b[:len(b)+bufLen] - } else { - b = append(b, make([]byte, bufLen)...) - } - - // Avoid expensive 64-bit divisions. - // We have at most 17 digits, and uint32 can store 9 digits. - // If the output doesn't fit into a uint32, cut off 8 digits - // so the rest will fit into a uint32. - var i int - if out>>32 > 0 { - var out32 uint32 - out, out32 = out/1e8, uint32(out%1e8) - for ; i < 8; i++ { - b[n+outLen-i] = '0' + byte(out32%10) - out32 /= 10 - } - } - out32 := uint32(out) - for ; i < outLen-1; i++ { - b[n+outLen-i] = '0' + byte(out32%10) - out32 /= 10 - } - b[n] = '0' + byte(out32%10) - - // Print the '.' if needed. - if outLen > 1 { - b[n+1] = '.' - } - - // Print the exponent. - b = append(b, 'e') - exp := d.e + int32(outLen) - 1 - if exp < 0 { - b = append(b, '-') - exp = -exp - } else { - // Unconditionally print a + here to match strconv's formatting. - b = append(b, '+') - } - // Always print at least two digits to match strconv's formatting. - d2 := exp % 10 - exp /= 10 - d1 := exp % 10 - d0 := exp / 10 - if d0 > 0 { - b = append(b, '0'+byte(d0)) - } - b = append(b, '0'+byte(d1), '0'+byte(d2)) - - return b -} - -func float64ToDecimalExactInt(mant, exp uint64) (d dec64, ok bool) { - e := exp - bias64 - if e > mantBits64 { - return d, false - } - shift := mantBits64 - e - mant |= 1 << mantBits64 // implicit 1 - d.m = mant >> shift - if d.m<= 0 { - // This expression is slightly faster than max(0, log10Pow2(e2) - 1). - q := log10Pow2(e2) - boolToUint32(e2 > 3) - e10 = int32(q) - k := pow5InvNumBits64 + pow5Bits(int32(q)) - 1 - i := -e2 + int32(q) + k - mul := pow5InvSplit64[q] - vr = mulShift64(4*m2, mul, i) - vp = mulShift64(4*m2+2, mul, i) - vm = mulShift64(4*m2-1-mmShift, mul, i) - if q <= 21 { - // This should use q <= 22, but I think 21 is also safe. - // Smaller values may still be safe, but it's more - // difficult to reason about them. Only one of mp, mv, - // and mm can be a multiple of 5, if any. - if mv%5 == 0 { - vrIsTrailingZeros = multipleOfPowerOfFive64(mv, q) - } else if acceptBounds { - // Same as min(e2 + (^mm & 1), pow5Factor64(mm)) >= q - // <=> e2 + (^mm & 1) >= q && pow5Factor64(mm) >= q - // <=> true && pow5Factor64(mm) >= q, since e2 >= q. - vmIsTrailingZeros = multipleOfPowerOfFive64(mv-1-mmShift, q) - } else if multipleOfPowerOfFive64(mv+2, q) { - vp-- - } - } - } else { - // This expression is slightly faster than max(0, log10Pow5(-e2) - 1). - q := log10Pow5(-e2) - boolToUint32(-e2 > 1) - e10 = int32(q) + e2 - i := -e2 - int32(q) - k := pow5Bits(i) - pow5NumBits64 - j := int32(q) - k - mul := pow5Split64[i] - vr = mulShift64(4*m2, mul, j) - vp = mulShift64(4*m2+2, mul, j) - vm = mulShift64(4*m2-1-mmShift, mul, j) - if q <= 1 { - // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. - // mv = 4 * m2, so it always has at least two trailing 0 bits. - vrIsTrailingZeros = true - if acceptBounds { - // mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1. - vmIsTrailingZeros = mmShift == 1 - } else { - // mp = mv + 2, so it always has at least one trailing 0 bit. - vp-- - } - } else if q < 63 { // TODO(ulfjack/cespare): Use a tighter bound here. - // We need to compute min(ntz(mv), pow5Factor64(mv) - e2) >= q - 1 - // <=> ntz(mv) >= q - 1 && pow5Factor64(mv) - e2 >= q - 1 - // <=> ntz(mv) >= q - 1 (e2 is negative and -e2 >= q) - // <=> (mv & ((1 << (q - 1)) - 1)) == 0 - // We also need to make sure that the left shift does not overflow. - vrIsTrailingZeros = multipleOfPowerOfTwo64(mv, q-1) - } - } - - // Step 4: Find the shortest decimal representation - // in the interval of valid representations. - var removed int32 - var lastRemovedDigit uint8 - var out uint64 - // On average, we remove ~2 digits. - if vmIsTrailingZeros || vrIsTrailingZeros { - // General case, which happens rarely (~0.7%). - for { - vpDiv10 := vp / 10 - vmDiv10 := vm / 10 - if vpDiv10 <= vmDiv10 { - break - } - vmMod10 := vm % 10 - vrDiv10 := vr / 10 - vrMod10 := vr % 10 - vmIsTrailingZeros = vmIsTrailingZeros && vmMod10 == 0 - vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 - lastRemovedDigit = uint8(vrMod10) - vr = vrDiv10 - vp = vpDiv10 - vm = vmDiv10 - removed++ - } - if vmIsTrailingZeros { - for { - vmDiv10 := vm / 10 - vmMod10 := vm % 10 - if vmMod10 != 0 { - break - } - vpDiv10 := vp / 10 - vrDiv10 := vr / 10 - vrMod10 := vr % 10 - vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 - lastRemovedDigit = uint8(vrMod10) - vr = vrDiv10 - vp = vpDiv10 - vm = vmDiv10 - removed++ - } - } - if vrIsTrailingZeros && lastRemovedDigit == 5 && vr%2 == 0 { - // Round even if the exact number is .....50..0. - lastRemovedDigit = 4 - } - out = vr - // We need to take vr + 1 if vr is outside bounds - // or we need to round up. - if (vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5 { - out++ - } - } else { - // Specialized for the common case (~99.3%). - // Percentages below are relative to this. - roundUp := false - for vp/100 > vm/100 { - // Optimization: remove two digits at a time (~86.2%). - roundUp = vr%100 >= 50 - vr /= 100 - vp /= 100 - vm /= 100 - removed += 2 - } - // Loop iterations below (approximately), without optimization above: - // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02% - // Loop iterations below (approximately), with optimization above: - // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02% - for vp/10 > vm/10 { - roundUp = vr%10 >= 5 - vr /= 10 - vp /= 10 - vm /= 10 - removed++ - } - // We need to take vr + 1 if vr is outside bounds - // or we need to round up. - out = vr + boolToUint64(vr == vm || roundUp) - } - - return dec64{m: out, e: e10 + removed} -} - -var powersOf10 = [...]uint64{ - 1e0, - 1e1, - 1e2, - 1e3, - 1e4, - 1e5, - 1e6, - 1e7, - 1e8, - 1e9, - 1e10, - 1e11, - 1e12, - 1e13, - 1e14, - 1e15, - 1e16, - 1e17, - // We only need to find the length of at most 17 digit numbers. -} - -func decimalLen64(u uint64) int { - // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - log2 := 64 - bits.LeadingZeros64(u) - 1 - t := (log2 + 1) * 1233 >> 12 - return t - boolToInt(u < powersOf10[t]) + 1 -} - -func mulShift64(m uint64, mul uint128, shift int32) uint64 { - hihi, hilo := bits.Mul64(m, mul.hi) - lohi, _ := bits.Mul64(m, mul.lo) - sum := uint128{hi: hihi, lo: lohi + hilo} - if sum.lo < lohi { - sum.hi++ // overflow - } - return shiftRight128(sum, shift-64) -} - -func shiftRight128(v uint128, shift int32) uint64 { - // The shift value is always modulo 64. - // In the current implementation of the 64-bit version - // of Ryu, the shift value is always < 64. - // (It is in the range [2, 59].) - // Check this here in case a future change requires larger shift - // values. In this case this function needs to be adjusted. - assert(shift < 64, "shift < 64") - return (v.hi << uint64(64-shift)) | (v.lo >> uint(shift)) -} - -func pow5Factor64(v uint64) uint32 { - for n := uint32(0); ; n++ { - q, r := v/5, v%5 - if r != 0 { - return n - } - v = q - } -} - -func multipleOfPowerOfFive64(v uint64, p uint32) bool { - return pow5Factor64(v) >= p -} - -func multipleOfPowerOfTwo64(v uint64, p uint32) bool { - return uint32(bits.TrailingZeros64(v)) >= p -} diff --git a/examples/gno.land/p/demo/json/ryu/table.gno b/examples/gno.land/p/demo/json/ryu/table.gno deleted file mode 100644 index fe33ad90a57..00000000000 --- a/examples/gno.land/p/demo/json/ryu/table.gno +++ /dev/null @@ -1,678 +0,0 @@ -// Code generated by running "go generate". DO NOT EDIT. - -// Copyright 2018 Ulf Adams -// Modifications copyright 2019 Caleb Spare -// -// The contents of this file may be used under the terms of the Apache License, -// Version 2.0. -// -// (See accompanying file LICENSE or copy at -// http://www.apache.org/licenses/LICENSE-2.0) -// -// Unless required by applicable law or agreed to in writing, this software -// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. -// -// The code in this file is part of a Go translation of the C code written by -// Ulf Adams which may be found at https://github.com/ulfjack/ryu. That source -// code is licensed under Apache 2.0 and this code is derivative work thereof. - -package ryu - -const pow5NumBits32 = 61 - -var pow5Split32 = [...]uint64{ - 1152921504606846976, 1441151880758558720, 1801439850948198400, 2251799813685248000, - 1407374883553280000, 1759218604441600000, 2199023255552000000, 1374389534720000000, - 1717986918400000000, 2147483648000000000, 1342177280000000000, 1677721600000000000, - 2097152000000000000, 1310720000000000000, 1638400000000000000, 2048000000000000000, - 1280000000000000000, 1600000000000000000, 2000000000000000000, 1250000000000000000, - 1562500000000000000, 1953125000000000000, 1220703125000000000, 1525878906250000000, - 1907348632812500000, 1192092895507812500, 1490116119384765625, 1862645149230957031, - 1164153218269348144, 1455191522836685180, 1818989403545856475, 2273736754432320594, - 1421085471520200371, 1776356839400250464, 2220446049250313080, 1387778780781445675, - 1734723475976807094, 2168404344971008868, 1355252715606880542, 1694065894508600678, - 2117582368135750847, 1323488980084844279, 1654361225106055349, 2067951531382569187, - 1292469707114105741, 1615587133892632177, 2019483917365790221, -} - -const pow5InvNumBits32 = 59 - -var pow5InvSplit32 = [...]uint64{ - 576460752303423489, 461168601842738791, 368934881474191033, 295147905179352826, - 472236648286964522, 377789318629571618, 302231454903657294, 483570327845851670, - 386856262276681336, 309485009821345069, 495176015714152110, 396140812571321688, - 316912650057057351, 507060240091291761, 405648192073033409, 324518553658426727, - 519229685853482763, 415383748682786211, 332306998946228969, 531691198313966350, - 425352958651173080, 340282366920938464, 544451787073501542, 435561429658801234, - 348449143727040987, 557518629963265579, 446014903970612463, 356811923176489971, - 570899077082383953, 456719261665907162, 365375409332725730, -} - -const pow5NumBits64 = 121 - -var pow5Split64 = [...]uint128{ - {0, 72057594037927936}, - {0, 90071992547409920}, - {0, 112589990684262400}, - {0, 140737488355328000}, - {0, 87960930222080000}, - {0, 109951162777600000}, - {0, 137438953472000000}, - {0, 85899345920000000}, - {0, 107374182400000000}, - {0, 134217728000000000}, - {0, 83886080000000000}, - {0, 104857600000000000}, - {0, 131072000000000000}, - {0, 81920000000000000}, - {0, 102400000000000000}, - {0, 128000000000000000}, - {0, 80000000000000000}, - {0, 100000000000000000}, - {0, 125000000000000000}, - {0, 78125000000000000}, - {0, 97656250000000000}, - {0, 122070312500000000}, - {0, 76293945312500000}, - {0, 95367431640625000}, - {0, 119209289550781250}, - {4611686018427387904, 74505805969238281}, - {10376293541461622784, 93132257461547851}, - {8358680908399640576, 116415321826934814}, - {612489549322387456, 72759576141834259}, - {14600669991935148032, 90949470177292823}, - {13639151471491547136, 113686837721616029}, - {3213881284082270208, 142108547152020037}, - {4314518811765112832, 88817841970012523}, - {781462496279003136, 111022302462515654}, - {10200200157203529728, 138777878078144567}, - {13292654125893287936, 86736173798840354}, - {7392445620511834112, 108420217248550443}, - {4628871007212404736, 135525271560688054}, - {16728102434789916672, 84703294725430033}, - {7075069988205232128, 105879118406787542}, - {18067209522111315968, 132348898008484427}, - {8986162942105878528, 82718061255302767}, - {6621017659204960256, 103397576569128459}, - {3664586055578812416, 129246970711410574}, - {16125424340018921472, 80779356694631608}, - {1710036351314100224, 100974195868289511}, - {15972603494424788992, 126217744835361888}, - {9982877184015493120, 78886090522101180}, - {12478596480019366400, 98607613152626475}, - {10986559581596820096, 123259516440783094}, - {2254913720070624656, 77037197775489434}, - {12042014186943056628, 96296497219361792}, - {15052517733678820785, 120370621524202240}, - {9407823583549262990, 75231638452626400}, - {11759779479436578738, 94039548065783000}, - {14699724349295723422, 117549435082228750}, - {4575641699882439235, 73468396926392969}, - {10331238143280436948, 91835496157991211}, - {8302361660673158281, 114794370197489014}, - {1154580038986672043, 143492962746861268}, - {9944984561221445835, 89683101716788292}, - {12431230701526807293, 112103877145985365}, - {1703980321626345405, 140129846432481707}, - {17205888765512323542, 87581154020301066}, - {12283988920035628619, 109476442525376333}, - {1519928094762372062, 136845553156720417}, - {12479170105294952299, 85528470722950260}, - {15598962631618690374, 106910588403687825}, - {5663645234241199255, 133638235504609782}, - {17374836326682913246, 83523897190381113}, - {7883487353071477846, 104404871487976392}, - {9854359191339347308, 130506089359970490}, - {10770660513014479971, 81566305849981556}, - {13463325641268099964, 101957882312476945}, - {2994098996302961243, 127447352890596182}, - {15706369927971514489, 79654595556622613}, - {5797904354682229399, 99568244445778267}, - {2635694424925398845, 124460305557222834}, - {6258995034005762182, 77787690973264271}, - {3212057774079814824, 97234613716580339}, - {17850130272881932242, 121543267145725423}, - {18073860448192289507, 75964541966078389}, - {8757267504958198172, 94955677457597987}, - {6334898362770359811, 118694596821997484}, - {13182683513586250689, 74184123013748427}, - {11866668373555425458, 92730153767185534}, - {5609963430089506015, 115912692208981918}, - {17341285199088104971, 72445432630613698}, - {12453234462005355406, 90556790788267123}, - {10954857059079306353, 113195988485333904}, - {13693571323849132942, 141494985606667380}, - {17781854114260483896, 88434366004167112}, - {3780573569116053255, 110542957505208891}, - {114030942967678664, 138178696881511114}, - {4682955357782187069, 86361685550944446}, - {15077066234082509644, 107952106938680557}, - {5011274737320973344, 134940133673350697}, - {14661261756894078100, 84337583545844185}, - {4491519140835433913, 105421979432305232}, - {5614398926044292391, 131777474290381540}, - {12732371365632458552, 82360921431488462}, - {6692092170185797382, 102951151789360578}, - {17588487249587022536, 128688939736700722}, - {15604490549419276989, 80430587335437951}, - {14893927168346708332, 100538234169297439}, - {14005722942005997511, 125672792711621799}, - {15671105866394830300, 78545495444763624}, - {1142138259283986260, 98181869305954531}, - {15262730879387146537, 122727336632443163}, - {7233363790403272633, 76704585395276977}, - {13653390756431478696, 95880731744096221}, - {3231680390257184658, 119850914680120277}, - {4325643253124434363, 74906821675075173}, - {10018740084832930858, 93633527093843966}, - {3300053069186387764, 117041908867304958}, - {15897591223523656064, 73151193042065598}, - {10648616992549794273, 91438991302581998}, - {4087399203832467033, 114298739128227498}, - {14332621041645359599, 142873423910284372}, - {18181260187883125557, 89295889943927732}, - {4279831161144355331, 111619862429909666}, - {14573160988285219972, 139524828037387082}, - {13719911636105650386, 87203017523366926}, - {7926517508277287175, 109003771904208658}, - {684774848491833161, 136254714880260823}, - {7345513307948477581, 85159196800163014}, - {18405263671790372785, 106448996000203767}, - {18394893571310578077, 133061245000254709}, - {13802651491282805250, 83163278125159193}, - {3418256308821342851, 103954097656448992}, - {4272820386026678563, 129942622070561240}, - {2670512741266674102, 81214138794100775}, - {17173198981865506339, 101517673492625968}, - {3019754653622331308, 126897091865782461}, - {4193189667727651020, 79310682416114038}, - {14464859121514339583, 99138353020142547}, - {13469387883465536574, 123922941275178184}, - {8418367427165960359, 77451838296986365}, - {15134645302384838353, 96814797871232956}, - {471562554271496325, 121018497339041196}, - {9518098633274461011, 75636560836900747}, - {7285937273165688360, 94545701046125934}, - {18330793628311886258, 118182126307657417}, - {4539216990053847055, 73863828942285886}, - {14897393274422084627, 92329786177857357}, - {4786683537745442072, 115412232722321697}, - {14520892257159371055, 72132645451451060}, - {18151115321449213818, 90165806814313825}, - {8853836096529353561, 112707258517892282}, - {1843923083806916143, 140884073147365353}, - {12681666973447792349, 88052545717103345}, - {2017025661527576725, 110065682146379182}, - {11744654113764246714, 137582102682973977}, - {422879793461572340, 85988814176858736}, - {528599741826965425, 107486017721073420}, - {660749677283706782, 134357522151341775}, - {7330497575943398595, 83973451344588609}, - {13774807988356636147, 104966814180735761}, - {3383451930163631472, 131208517725919702}, - {15949715511634433382, 82005323578699813}, - {6102086334260878016, 102506654473374767}, - {3015921899398709616, 128133318091718459}, - {18025852251620051174, 80083323807324036}, - {4085571240815512351, 100104154759155046}, - {14330336087874166247, 125130193448943807}, - {15873989082562435760, 78206370905589879}, - {15230800334775656796, 97757963631987349}, - {5203442363187407284, 122197454539984187}, - {946308467778435600, 76373409087490117}, - {5794571603150432404, 95466761359362646}, - {16466586540792816313, 119333451699203307}, - {7985773578781816244, 74583407312002067}, - {5370530955049882401, 93229259140002584}, - {6713163693812353001, 116536573925003230}, - {18030785363914884337, 72835358703127018}, - {13315109668038829614, 91044198378908773}, - {2808829029766373305, 113805247973635967}, - {17346094342490130344, 142256559967044958}, - {6229622945628943561, 88910349979403099}, - {3175342663608791547, 111137937474253874}, - {13192550366365765242, 138922421842817342}, - {3633657960551215372, 86826513651760839}, - {18377130505971182927, 108533142064701048}, - {4524669058754427043, 135666427580876311}, - {9745447189362598758, 84791517238047694}, - {2958436949848472639, 105989396547559618}, - {12921418224165366607, 132486745684449522}, - {12687572408530742033, 82804216052780951}, - {11247779492236039638, 103505270065976189}, - {224666310012885835, 129381587582470237}, - {2446259452971747599, 80863492239043898}, - {12281196353069460307, 101079365298804872}, - {15351495441336825384, 126349206623506090}, - {14206370669262903769, 78968254139691306}, - {8534591299723853903, 98710317674614133}, - {15279925143082205283, 123387897093267666}, - {14161639232853766206, 77117435683292291}, - {13090363022639819853, 96396794604115364}, - {16362953778299774816, 120495993255144205}, - {12532689120651053212, 75309995784465128}, - {15665861400813816515, 94137494730581410}, - {10358954714162494836, 117671868413226763}, - {4168503687137865320, 73544917758266727}, - {598943590494943747, 91931147197833409}, - {5360365506546067587, 114913933997291761}, - {11312142901609972388, 143642417496614701}, - {9375932322719926695, 89776510935384188}, - {11719915403399908368, 112220638669230235}, - {10038208235822497557, 140275798336537794}, - {10885566165816448877, 87672373960336121}, - {18218643725697949000, 109590467450420151}, - {18161618638695048346, 136988084313025189}, - {13656854658398099168, 85617552695640743}, - {12459382304570236056, 107021940869550929}, - {1739169825430631358, 133777426086938662}, - {14922039196176308311, 83610891304336663}, - {14040862976792997485, 104513614130420829}, - {3716020665709083144, 130642017663026037}, - {4628355925281870917, 81651261039391273}, - {10397130925029726550, 102064076299239091}, - {8384727637859770284, 127580095374048864}, - {5240454773662356427, 79737559608780540}, - {6550568467077945534, 99671949510975675}, - {3576524565420044014, 124589936888719594}, - {6847013871814915412, 77868710555449746}, - {17782139376623420074, 97335888194312182}, - {13004302183924499284, 121669860242890228}, - {17351060901807587860, 76043662651806392}, - {3242082053549933210, 95054578314757991}, - {17887660622219580224, 118818222893447488}, - {11179787888887237640, 74261389308404680}, - {13974734861109047050, 92826736635505850}, - {8245046539531533005, 116033420794382313}, - {16682369133275677888, 72520887996488945}, - {7017903361312433648, 90651109995611182}, - {17995751238495317868, 113313887494513977}, - {8659630992836983623, 141642359368142472}, - {5412269370523114764, 88526474605089045}, - {11377022731581281359, 110658093256361306}, - {4997906377621825891, 138322616570451633}, - {14652906532082110942, 86451635356532270}, - {9092761128247862869, 108064544195665338}, - {2142579373455052779, 135080680244581673}, - {12868327154477877747, 84425425152863545}, - {2250350887815183471, 105531781441079432}, - {2812938609768979339, 131914726801349290}, - {6369772649532999991, 82446704250843306}, - {17185587848771025797, 103058380313554132}, - {3035240737254230630, 128822975391942666}, - {6508711479211282048, 80514359619964166}, - {17359261385868878368, 100642949524955207}, - {17087390713908710056, 125803686906194009}, - {3762090168551861929, 78627304316371256}, - {4702612710689827411, 98284130395464070}, - {15101637925217060072, 122855162994330087}, - {16356052730901744401, 76784476871456304}, - {1998321839917628885, 95980596089320381}, - {7109588318324424010, 119975745111650476}, - {13666864735807540814, 74984840694781547}, - {12471894901332038114, 93731050868476934}, - {6366496589810271835, 117163813585596168}, - {3979060368631419896, 73227383490997605}, - {9585511479216662775, 91534229363747006}, - {2758517312166052660, 114417786704683758}, - {12671518677062341634, 143022233380854697}, - {1002170145522881665, 89388895863034186}, - {10476084718758377889, 111736119828792732}, - {13095105898447972362, 139670149785990915}, - {5878598177316288774, 87293843616244322}, - {16571619758500136775, 109117304520305402}, - {11491152661270395161, 136396630650381753}, - {264441385652915120, 85247894156488596}, - {330551732066143900, 106559867695610745}, - {5024875683510067779, 133199834619513431}, - {10058076329834874218, 83249896637195894}, - {3349223375438816964, 104062370796494868}, - {4186529219298521205, 130077963495618585}, - {14145795808130045513, 81298727184761615}, - {13070558741735168987, 101623408980952019}, - {11726512408741573330, 127029261226190024}, - {7329070255463483331, 79393288266368765}, - {13773023837756742068, 99241610332960956}, - {17216279797195927585, 124052012916201195}, - {8454331864033760789, 77532508072625747}, - {5956228811614813082, 96915635090782184}, - {7445286014518516353, 121144543863477730}, - {9264989777501460624, 75715339914673581}, - {16192923240304213684, 94644174893341976}, - {1794409976670715490, 118305218616677471}, - {8039035263060279037, 73940761635423419}, - {5437108060397960892, 92425952044279274}, - {16019757112352226923, 115532440055349092}, - {788976158365366019, 72207775034593183}, - {14821278253238871236, 90259718793241478}, - {9303225779693813237, 112824648491551848}, - {11629032224617266546, 141030810614439810}, - {11879831158813179495, 88144256634024881}, - {1014730893234310657, 110180320792531102}, - {10491785653397664129, 137725400990663877}, - {8863209042587234033, 86078375619164923}, - {6467325284806654637, 107597969523956154}, - {17307528642863094104, 134497461904945192}, - {10817205401789433815, 84060913690590745}, - {18133192770664180173, 105076142113238431}, - {18054804944902837312, 131345177641548039}, - {18201782118205355176, 82090736025967524}, - {4305483574047142354, 102613420032459406}, - {14605226504413703751, 128266775040574257}, - {2210737537617482988, 80166734400358911}, - {16598479977304017447, 100208418000448638}, - {11524727934775246001, 125260522500560798}, - {2591268940807140847, 78287826562850499}, - {17074144231291089770, 97859783203563123}, - {16730994270686474309, 122324729004453904}, - {10456871419179046443, 76452955627783690}, - {3847717237119032246, 95566194534729613}, - {9421332564826178211, 119457743168412016}, - {5888332853016361382, 74661089480257510}, - {16583788103125227536, 93326361850321887}, - {16118049110479146516, 116657952312902359}, - {16991309721690548428, 72911220195563974}, - {12015765115258409727, 91139025244454968}, - {15019706394073012159, 113923781555568710}, - {9551260955736489391, 142404726944460888}, - {5969538097335305869, 89002954340288055}, - {2850236603241744433, 111253692925360069}, -} - -const pow5InvNumBits64 = 122 - -var pow5InvSplit64 = [...]uint128{ - {1, 288230376151711744}, - {3689348814741910324, 230584300921369395}, - {2951479051793528259, 184467440737095516}, - {17118578500402463900, 147573952589676412}, - {12632330341676300947, 236118324143482260}, - {10105864273341040758, 188894659314785808}, - {15463389048156653253, 151115727451828646}, - {17362724847566824558, 241785163922925834}, - {17579528692795369969, 193428131138340667}, - {6684925324752475329, 154742504910672534}, - {18074578149087781173, 247588007857076054}, - {18149011334012135262, 198070406285660843}, - {3451162622983977240, 158456325028528675}, - {5521860196774363583, 253530120045645880}, - {4417488157419490867, 202824096036516704}, - {7223339340677503017, 162259276829213363}, - {7867994130342094503, 259614842926741381}, - {2605046489531765280, 207691874341393105}, - {2084037191625412224, 166153499473114484}, - {10713157136084480204, 265845599156983174}, - {12259874523609494487, 212676479325586539}, - {13497248433629505913, 170141183460469231}, - {14216899864323388813, 272225893536750770}, - {11373519891458711051, 217780714829400616}, - {5409467098425058518, 174224571863520493}, - {4965798542738183305, 278759314981632789}, - {7661987648932456967, 223007451985306231}, - {2440241304404055250, 178405961588244985}, - {3904386087046488400, 285449538541191976}, - {17880904128604832013, 228359630832953580}, - {14304723302883865611, 182687704666362864}, - {15133127457049002812, 146150163733090291}, - {16834306301794583852, 233840261972944466}, - {9778096226693756759, 187072209578355573}, - {15201174610838826053, 149657767662684458}, - {2185786488890659746, 239452428260295134}, - {5437978005854438120, 191561942608236107}, - {15418428848909281466, 153249554086588885}, - {6222742084545298729, 245199286538542217}, - {16046240111861969953, 196159429230833773}, - {1768945645263844993, 156927543384667019}, - {10209010661905972635, 251084069415467230}, - {8167208529524778108, 200867255532373784}, - {10223115638361732810, 160693804425899027}, - {1599589762411131202, 257110087081438444}, - {4969020624670815285, 205688069665150755}, - {3975216499736652228, 164550455732120604}, - {13739044029062464211, 263280729171392966}, - {7301886408508061046, 210624583337114373}, - {13220206756290269483, 168499666669691498}, - {17462981995322520850, 269599466671506397}, - {6591687966774196033, 215679573337205118}, - {12652048002903177473, 172543658669764094}, - {9175230360419352987, 276069853871622551}, - {3650835473593572067, 220855883097298041}, - {17678063637842498946, 176684706477838432}, - {13527506561580357021, 282695530364541492}, - {3443307619780464970, 226156424291633194}, - {6443994910566282300, 180925139433306555}, - {5155195928453025840, 144740111546645244}, - {15627011115008661990, 231584178474632390}, - {12501608892006929592, 185267342779705912}, - {2622589484121723027, 148213874223764730}, - {4196143174594756843, 237142198758023568}, - {10735612169159626121, 189713759006418854}, - {12277838550069611220, 151771007205135083}, - {15955192865369467629, 242833611528216133}, - {1696107848069843133, 194266889222572907}, - {12424932722681605476, 155413511378058325}, - {1433148282581017146, 248661618204893321}, - {15903913885032455010, 198929294563914656}, - {9033782293284053685, 159143435651131725}, - {14454051669254485895, 254629497041810760}, - {11563241335403588716, 203703597633448608}, - {16629290697806691620, 162962878106758886}, - {781423413297334329, 260740604970814219}, - {4314487545379777786, 208592483976651375}, - {3451590036303822229, 166873987181321100}, - {5522544058086115566, 266998379490113760}, - {4418035246468892453, 213598703592091008}, - {10913125826658934609, 170878962873672806}, - {10082303693170474728, 273406340597876490}, - {8065842954536379782, 218725072478301192}, - {17520720807854834795, 174980057982640953}, - {5897060404116273733, 279968092772225526}, - {1028299508551108663, 223974474217780421}, - {15580034865808528224, 179179579374224336}, - {17549358155809824511, 286687326998758938}, - {2971440080422128639, 229349861599007151}, - {17134547323305344204, 183479889279205720}, - {13707637858644275364, 146783911423364576}, - {14553522944347019935, 234854258277383322}, - {4264120725993795302, 187883406621906658}, - {10789994210278856888, 150306725297525326}, - {9885293106962350374, 240490760476040522}, - {529536856086059653, 192392608380832418}, - {7802327114352668369, 153914086704665934}, - {1415676938738538420, 246262538727465495}, - {1132541550990830736, 197010030981972396}, - {15663428499760305882, 157608024785577916}, - {17682787970132668764, 252172839656924666}, - {10456881561364224688, 201738271725539733}, - {15744202878575200397, 161390617380431786}, - {17812026976236499989, 258224987808690858}, - {3181575136763469022, 206579990246952687}, - {13613306553636506187, 165263992197562149}, - {10713244041592678929, 264422387516099439}, - {12259944048016053467, 211537910012879551}, - {6118606423670932450, 169230328010303641}, - {2411072648389671274, 270768524816485826}, - {16686253377679378312, 216614819853188660}, - {13349002702143502650, 173291855882550928}, - {17669055508687693916, 277266969412081485}, - {14135244406950155133, 221813575529665188}, - {240149081334393137, 177450860423732151}, - {11452284974360759988, 283921376677971441}, - {5472479164746697667, 227137101342377153}, - {11756680961281178780, 181709681073901722}, - {2026647139541122378, 145367744859121378}, - {18000030682233437097, 232588391774594204}, - {18089373360528660001, 186070713419675363}, - {3403452244197197031, 148856570735740291}, - {16513570034941246220, 238170513177184465}, - {13210856027952996976, 190536410541747572}, - {3189987192878576934, 152429128433398058}, - {1414630693863812771, 243886605493436893}, - {8510402184574870864, 195109284394749514}, - {10497670562401807014, 156087427515799611}, - {9417575270359070576, 249739884025279378}, - {14912757845771077107, 199791907220223502}, - {4551508647133041040, 159833525776178802}, - {10971762650154775986, 255733641241886083}, - {16156107749607641435, 204586912993508866}, - {9235537384944202825, 163669530394807093}, - {11087511001168814197, 261871248631691349}, - {12559357615676961681, 209496998905353079}, - {13736834907283479668, 167597599124282463}, - {18289587036911657145, 268156158598851941}, - {10942320814787415393, 214524926879081553}, - {16132554281313752961, 171619941503265242}, - {11054691591134363444, 274591906405224388}, - {16222450902391311402, 219673525124179510}, - {12977960721913049122, 175738820099343608}, - {17075388340318968271, 281182112158949773}, - {2592264228029443648, 224945689727159819}, - {5763160197165465241, 179956551781727855}, - {9221056315464744386, 287930482850764568}, - {14755542681855616155, 230344386280611654}, - {15493782960226403247, 184275509024489323}, - {1326979923955391628, 147420407219591459}, - {9501865507812447252, 235872651551346334}, - {11290841220991868125, 188698121241077067}, - {1653975347309673853, 150958496992861654}, - {10025058185179298811, 241533595188578646}, - {4330697733401528726, 193226876150862917}, - {14532604630946953951, 154581500920690333}, - {1116074521063664381, 247330401473104534}, - {4582208431592841828, 197864321178483627}, - {14733813189500004432, 158291456942786901}, - {16195403473716186445, 253266331108459042}, - {5577625149489128510, 202613064886767234}, - {8151448934333213131, 162090451909413787}, - {16731667109675051333, 259344723055062059}, - {17074682502481951390, 207475778444049647}, - {6281048372501740465, 165980622755239718}, - {6360328581260874421, 265568996408383549}, - {8777611679750609860, 212455197126706839}, - {10711438158542398211, 169964157701365471}, - {9759603424184016492, 271942652322184754}, - {11497031554089123517, 217554121857747803}, - {16576322872755119460, 174043297486198242}, - {11764721337440549842, 278469275977917188}, - {16790474699436260520, 222775420782333750}, - {13432379759549008416, 178220336625867000}, - {3045063541568861850, 285152538601387201}, - {17193446092222730773, 228122030881109760}, - {13754756873778184618, 182497624704887808}, - {18382503128506368341, 145998099763910246}, - {3586563302416817083, 233596959622256395}, - {2869250641933453667, 186877567697805116}, - {17052795772514404226, 149502054158244092}, - {12527077977055405469, 239203286653190548}, - {17400360011128145022, 191362629322552438}, - {2852241564676785048, 153090103458041951}, - {15631632947708587046, 244944165532867121}, - {8815957543424959314, 195955332426293697}, - {18120812478965698421, 156764265941034957}, - {14235904707377476180, 250822825505655932}, - {4010026136418160298, 200658260404524746}, - {17965416168102169531, 160526608323619796}, - {2919224165770098987, 256842573317791675}, - {2335379332616079190, 205474058654233340}, - {1868303466092863352, 164379246923386672}, - {6678634360490491686, 263006795077418675}, - {5342907488392393349, 210405436061934940}, - {4274325990713914679, 168324348849547952}, - {10528270399884173809, 269318958159276723}, - {15801313949391159694, 215455166527421378}, - {1573004715287196786, 172364133221937103}, - {17274202803427156150, 275782613155099364}, - {17508711057483635243, 220626090524079491}, - {10317620031244997871, 176500872419263593}, - {12818843235250086271, 282401395870821749}, - {13944423402941979340, 225921116696657399}, - {14844887537095493795, 180736893357325919}, - {15565258844418305359, 144589514685860735}, - {6457670077359736959, 231343223497377177}, - {16234182506113520537, 185074578797901741}, - {9297997190148906106, 148059663038321393}, - {11187446689496339446, 236895460861314229}, - {12639306166338981880, 189516368689051383}, - {17490142562555006151, 151613094951241106}, - {2158786396894637579, 242580951921985771}, - {16484424376483351356, 194064761537588616}, - {9498190686444770762, 155251809230070893}, - {11507756283569722895, 248402894768113429}, - {12895553841597688639, 198722315814490743}, - {17695140702761971558, 158977852651592594}, - {17244178680193423523, 254364564242548151}, - {10105994129412828495, 203491651394038521}, - {4395446488788352473, 162793321115230817}, - {10722063196803274280, 260469313784369307}, - {1198952927958798777, 208375451027495446}, - {15716557601334680315, 166700360821996356}, - {17767794532651667857, 266720577315194170}, - {14214235626121334286, 213376461852155336}, - {7682039686155157106, 170701169481724269}, - {1223217053622520399, 273121871170758831}, - {15735968901865657612, 218497496936607064}, - {16278123936234436413, 174797997549285651}, - {219556594781725998, 279676796078857043}, - {7554342905309201445, 223741436863085634}, - {9732823138989271479, 178993149490468507}, - {815121763415193074, 286389039184749612}, - {11720143854957885429, 229111231347799689}, - {13065463898708218666, 183288985078239751}, - {6763022304224664610, 146631188062591801}, - {3442138057275642729, 234609900900146882}, - {13821756890046245153, 187687920720117505}, - {11057405512036996122, 150150336576094004}, - {6623802375033462826, 240240538521750407}, - {16367088344252501231, 192192430817400325}, - {13093670675402000985, 153753944653920260}, - {2503129006933649959, 246006311446272417}, - {13070549649772650937, 196805049157017933}, - {17835137349301941396, 157444039325614346}, - {2710778055689733971, 251910462920982955}, - {2168622444551787177, 201528370336786364}, - {5424246770383340065, 161222696269429091}, - {1300097203129523457, 257956314031086546}, - {15797473021471260058, 206365051224869236}, - {8948629602435097724, 165092040979895389}, - {3249760919670425388, 264147265567832623}, - {9978506365220160957, 211317812454266098}, - {15361502721659949412, 169054249963412878}, - {2442311466204457120, 270486799941460606}, - {16711244431931206989, 216389439953168484}, - {17058344360286875914, 173111551962534787}, - {12535955717491360170, 276978483140055660}, - {10028764573993088136, 221582786512044528}, - {15401709288678291155, 177266229209635622}, - {9885339602917624555, 283625966735416996}, - {4218922867592189321, 226900773388333597}, - {14443184738299482427, 181520618710666877}, - {4175850161155765295, 145216494968533502}, - {10370709072591134795, 232346391949653603}, - {15675264887556728482, 185877113559722882}, - {5161514280561562140, 148701690847778306}, - {879725219414678777, 237922705356445290}, - {703780175531743021, 190338164285156232}, - {11631070584651125387, 152270531428124985}, - {162968861732249003, 243632850284999977}, - {11198421533611530172, 194906280227999981}, - {5269388412147313814, 155925024182399985}, - {8431021459435702103, 249480038691839976}, - {3055468352806651359, 199584030953471981}, - {17201769941212962380, 159667224762777584}, - {16454785461715008838, 255467559620444135}, - {13163828369372007071, 204374047696355308}, - {17909760324981426303, 163499238157084246}, - {2830174816776909822, 261598781051334795}, - {2264139853421527858, 209279024841067836}, - {16568707141704863579, 167423219872854268}, - {4373838538276319787, 267877151796566830}, - {3499070830621055830, 214301721437253464}, - {6488605479238754987, 171441377149802771}, - {3003071137298187333, 274306203439684434}, - {6091805724580460189, 219444962751747547}, - {15941491023890099121, 175555970201398037}, - {10748990379256517301, 280889552322236860}, - {8599192303405213841, 224711641857789488}, - {14258051472207991719, 179769313486231590}, -} From e9640ef55dc3d0bb0022a50557550bf6316b9953 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Wed, 30 Oct 2024 22:21:43 +0100 Subject: [PATCH 61/64] test(gno.land): add unit tests for sdk/vm.vmHandler (#2459) ```console gnome$ go test -v ./sdk/vm -run TestVmHandler === RUN TestVmHandlerQuery_Eval === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.Echo("hello") === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.PubString === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.ConstString === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.pvString === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.counter === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.GetCounter() === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.Inc() === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.pvEcho("hello") === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.1337 === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.13.37 === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.float64(1337) === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.myStructInst === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.myStructInst.Foo() === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.myStruct === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.Inc === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.fn()("hi") === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.sl === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.sl[1] === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.println(1234) 1234 === RUN TestVmHandlerQuery_Eval/gno.land/r/hello === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.doesnotexist === RUN TestVmHandlerQuery_Eval/gno.land/r/doesnotexist.Foo === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.Panic() === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.panic("bar") === RUN TestVmHandlerQuery_Eval/gno.land/r/hello.sl[6] --- PASS: TestVmHandlerQuery_Eval (0.03s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.Echo("hello") (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.PubString (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.ConstString (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.pvString (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.counter (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.GetCounter() (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.Inc() (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.pvEcho("hello") (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.1337 (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.13.37 (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.float64(1337) (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.myStructInst (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.myStructInst.Foo() (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.myStruct (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.Inc (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.fn()("hi") (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.sl (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.sl[1] (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.println(1234) (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.doesnotexist (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/doesnotexist.Foo (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.Panic() (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.panic("bar") (0.00s) --- PASS: TestVmHandlerQuery_Eval/gno.land/r/hello.sl[6] (0.00s) === RUN TestVmHandlerQuery_Funcs === RUN TestVmHandlerQuery_Funcs/gno.land/r/hello === RUN TestVmHandlerQuery_Funcs/gno.land/r/doesnotexist === RUN TestVmHandlerQuery_Funcs/std === RUN TestVmHandlerQuery_Funcs/strings --- PASS: TestVmHandlerQuery_Funcs (0.00s) --- PASS: TestVmHandlerQuery_Funcs/gno.land/r/hello (0.00s) --- PASS: TestVmHandlerQuery_Funcs/gno.land/r/doesnotexist (0.00s) --- PASS: TestVmHandlerQuery_Funcs/std (0.00s) --- PASS: TestVmHandlerQuery_Funcs/strings (0.00s) === RUN TestVmHandlerQuery_File === RUN TestVmHandlerQuery_File/gno.land/r/hello/hello.gno === RUN TestVmHandlerQuery_File/gno.land/r/hello/README.md === RUN TestVmHandlerQuery_File/gno.land/r/hello/doesnotexist.gno === RUN TestVmHandlerQuery_File/gno.land/r/hello === RUN TestVmHandlerQuery_File/gno.land/r/doesnotexist === RUN TestVmHandlerQuery_File/gno.land/r/doesnotexist/hello.gno --- PASS: TestVmHandlerQuery_File (0.00s) --- PASS: TestVmHandlerQuery_File/gno.land/r/hello/hello.gno (0.00s) --- PASS: TestVmHandlerQuery_File/gno.land/r/hello/README.md (0.00s) --- PASS: TestVmHandlerQuery_File/gno.land/r/hello/doesnotexist.gno (0.00s) --- PASS: TestVmHandlerQuery_File/gno.land/r/hello (0.00s) --- PASS: TestVmHandlerQuery_File/gno.land/r/doesnotexist (0.00s) --- PASS: TestVmHandlerQuery_File/gno.land/r/doesnotexist/hello.gno (0.00s) PASS ok github.com/gnolang/gno/gno.land/pkg/sdk/vm (cached) ``` --------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- gno.land/pkg/sdk/vm/common_test.go | 4 +- gno.land/pkg/sdk/vm/gas_test.go | 3 +- gno.land/pkg/sdk/vm/handler_test.go | 274 ++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 3 deletions(-) diff --git a/gno.land/pkg/sdk/vm/common_test.go b/gno.land/pkg/sdk/vm/common_test.go index 7380d3e0f72..8b1b7d909c1 100644 --- a/gno.land/pkg/sdk/vm/common_test.go +++ b/gno.land/pkg/sdk/vm/common_test.go @@ -23,6 +23,7 @@ type testEnv struct { vmk *VMKeeper bank bankm.BankKeeper acck authm.AccountKeeper + vmh vmHandler } func setupTestEnv() testEnv { @@ -62,6 +63,7 @@ func _setupTestEnv(cacheStdlibs bool) testEnv { } vmk.CommitGnoTransactionStore(stdlibCtx) mcw.MultiWrite() + vmh := NewHandler(vmk) - return testEnv{ctx: ctx, vmk: vmk, bank: bank, acck: acck} + return testEnv{ctx: ctx, vmk: vmk, bank: bank, acck: acck, vmh: vmh} } diff --git a/gno.land/pkg/sdk/vm/gas_test.go b/gno.land/pkg/sdk/vm/gas_test.go index a199f12898a..ff924610627 100644 --- a/gno.land/pkg/sdk/vm/gas_test.go +++ b/gno.land/pkg/sdk/vm/gas_test.go @@ -143,7 +143,6 @@ func setupAddPkg(success bool) (sdk.Context, sdk.Tx, vmHandler) { ctx := env.ctx // conduct base gas meter tests from a non-genesis block since genesis block use infinite gas meter instead. ctx = ctx.WithBlockHeader(&bft.Header{Height: int64(1)}) - vmHandler := NewHandler(env.vmk) // Create an account with 10M ugnot (10gnot) addr := crypto.AddressFromPreimage([]byte("test1")) acc := env.acck.NewAccountWithAddress(ctx, addr) @@ -183,5 +182,5 @@ func Echo() UnknowType { fee := std.NewFee(500000, std.MustParseCoin(ugnot.ValueString(1))) tx := std.NewTx(msgs, fee, []std.Signature{}, "") - return ctx, tx, vmHandler + return ctx, tx, env.vmh } diff --git a/gno.land/pkg/sdk/vm/handler_test.go b/gno.land/pkg/sdk/vm/handler_test.go index 38ac8fa61b9..7e029f4cacb 100644 --- a/gno.land/pkg/sdk/vm/handler_test.go +++ b/gno.land/pkg/sdk/vm/handler_test.go @@ -1,8 +1,13 @@ package vm import ( + "fmt" "testing" + "github.com/gnolang/gno/gnovm" + abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" + "github.com/gnolang/gno/tm2/pkg/crypto" + "github.com/gnolang/gno/tm2/pkg/std" "github.com/stretchr/testify/assert" ) @@ -48,3 +53,272 @@ func Test_parseQueryEval_panic(t *testing.T) { parseQueryEvalData("gno.land/r/demo/users") }) } + +func TestVmHandlerQuery_Eval(t *testing.T) { + tt := []struct { + input []byte + expectedResult string + expectedResultMatch string + expectedErrorMatch string + expectedPanicMatch string + // XXX: expectedEvents + }{ + // valid queries + {input: []byte(`gno.land/r/hello.Echo("hello")`), expectedResult: `("echo:hello" string)`}, + {input: []byte(`gno.land/r/hello.caller()`), expectedResult: `("" std.Address)`}, // FIXME? + {input: []byte(`gno.land/r/hello.GetHeight()`), expectedResult: `(0 int64)`}, + // {input: []byte(`gno.land/r/hello.time.RFC3339`), expectedResult: `test`}, // not working, but should we care? + {input: []byte(`gno.land/r/hello.PubString`), expectedResult: `("public string" string)`}, + {input: []byte(`gno.land/r/hello.ConstString`), expectedResult: `("const string" string)`}, + {input: []byte(`gno.land/r/hello.pvString`), expectedResult: `("private string" string)`}, + {input: []byte(`gno.land/r/hello.counter`), expectedResult: `(42 int)`}, + {input: []byte(`gno.land/r/hello.GetCounter()`), expectedResult: `(42 int)`}, + {input: []byte(`gno.land/r/hello.Inc()`), expectedResult: `(43 int)`}, + {input: []byte(`gno.land/r/hello.pvEcho("hello")`), expectedResult: `("pvecho:hello" string)`}, + {input: []byte(`gno.land/r/hello.1337`), expectedResult: `(1337 int)`}, + {input: []byte(`gno.land/r/hello.13.37`), expectedResult: `(13.37 float64)`}, + {input: []byte(`gno.land/r/hello.float64(1337)`), expectedResult: `(1337 float64)`}, + {input: []byte(`gno.land/r/hello.myStructInst`), expectedResult: `(struct{(1000 int)} gno.land/r/hello.myStruct)`}, + {input: []byte(`gno.land/r/hello.myStructInst.Foo()`), expectedResult: `("myStruct.Foo" string)`}, + {input: []byte(`gno.land/r/hello.myStruct`), expectedResultMatch: `\(typeval{gno.land/r/hello.myStruct \(0x.*\)} type{}\)`}, + {input: []byte(`gno.land/r/hello.Inc`), expectedResult: `(Inc func()( int))`}, + {input: []byte(`gno.land/r/hello.fn()("hi")`), expectedResult: `("echo:hi" string)`}, + {input: []byte(`gno.land/r/hello.sl`), expectedResultMatch: `(slice[ref(.*)] []int)`}, // XXX: should return the actual value + {input: []byte(`gno.land/r/hello.sl[1]`), expectedResultMatch: `(slice[ref(.*)] []int)`}, // XXX: should return the actual value + {input: []byte(`gno.land/r/hello.println(1234)`), expectedResultMatch: `^$`}, // XXX: compare stdout? + + // panics + {input: []byte(`gno.land/r/hello`), expectedPanicMatch: `expected . syntax in query input data`}, + + // errors + {input: []byte(`gno.land/r/hello.doesnotexist`), expectedErrorMatch: `^/:0:0: name doesnotexist not declared:`}, // multiline error + {input: []byte(`gno.land/r/doesnotexist.Foo`), expectedErrorMatch: `^invalid package path$`}, + {input: []byte(`gno.land/r/hello.Panic()`), expectedErrorMatch: `^foo$`}, + {input: []byte(`gno.land/r/hello.sl[6]`), expectedErrorMatch: `^slice index out of bounds: 6 \(len=5\)$`}, + } + + for _, tc := range tt { + name := string(tc.input) + t.Run(name, func(t *testing.T) { + env := setupTestEnv() + ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + vmHandler := env.vmh + + // 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("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + + // Create test package. + files := []*gnovm.MemFile{ + {"hello.gno", ` +package hello + +import "std" +import "time" + +var _ = time.RFC3339 +func caller() std.Address { return std.GetOrigCaller() } +var GetHeight = std.GetHeight +var sl = []int{1,2,3,4,5} +func fn() func(string) string { return Echo } +type myStruct struct{a int} +var myStructInst = myStruct{a: 1000} +func (ms myStruct) Foo() string { return "myStruct.Foo" } +func Panic() { panic("foo") } +var counter int = 42 +var pvString = "private string" +var PubString = "public string" +const ConstString = "const string" +func Echo(msg string) string { return "echo:"+msg } +func GetCounter() int { return counter } +func Inc() int { counter += 1; return counter } +func pvEcho(msg string) string { return "pvecho:"+msg } +`}, + } + pkgPath := "gno.land/r/hello" + msg1 := NewMsgAddPackage(addr, pkgPath, files) + err := env.vmk.AddPackage(ctx, msg1) + assert.NoError(t, err) + env.vmk.CommitGnoTransactionStore(ctx) + + req := abci.RequestQuery{ + Path: "vm/qeval", + Data: tc.input, + } + + defer func() { + if r := recover(); r != nil { + output := fmt.Sprintf("%v", r) + assert.Regexp(t, tc.expectedPanicMatch, output) + } else { + assert.Equal(t, tc.expectedPanicMatch, "", "should not panic") + } + }() + res := vmHandler.Query(env.ctx, req) + if tc.expectedPanicMatch == "" { + if tc.expectedErrorMatch == "" { + assert.True(t, res.IsOK(), "should not have error") + if tc.expectedResult != "" { + assert.Equal(t, string(res.Data), tc.expectedResult) + } + if tc.expectedResultMatch != "" { + assert.Regexp(t, tc.expectedResultMatch, string(res.Data)) + } + } else { + assert.False(t, res.IsOK(), "should have an error") + errmsg := res.Error.Error() + assert.Regexp(t, tc.expectedErrorMatch, errmsg) + } + } + }) + } +} + +func TestVmHandlerQuery_Funcs(t *testing.T) { + tt := []struct { + input []byte + expectedResult string + expectedErrorMatch string + }{ + // valid queries + {input: []byte(`gno.land/r/hello`), expectedResult: `[{"FuncName":"Panic","Params":null,"Results":null},{"FuncName":"Echo","Params":[{"Name":"msg","Type":"string","Value":""}],"Results":[{"Name":"_","Type":"string","Value":""}]},{"FuncName":"GetCounter","Params":null,"Results":[{"Name":"_","Type":"int","Value":""}]},{"FuncName":"Inc","Params":null,"Results":[{"Name":"_","Type":"int","Value":""}]}]`}, + {input: []byte(`gno.land/r/doesnotexist`), expectedErrorMatch: `invalid package path`}, + {input: []byte(`std`), expectedErrorMatch: `invalid package path`}, + {input: []byte(`strings`), expectedErrorMatch: `invalid package path`}, + } + + for _, tc := range tt { + name := string(tc.input) + t.Run(name, func(t *testing.T) { + env := setupTestEnv() + ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + vmHandler := env.vmh + + // 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("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + + // Create test package. + files := []*gnovm.MemFile{ + {"hello.gno", ` +package hello + +var sl = []int{1,2,3,4,5} +func fn() func(string) string { return Echo } +type myStruct struct{a int} +var myStructInst = myStruct{a: 1000} +func (ms myStruct) Foo() string { return "myStruct.Foo" } +func Panic() { panic("foo") } +var counter int = 42 +var pvString = "private string" +var PubString = "public string" +const ConstString = "const string" +func Echo(msg string) string { return "echo:"+msg } +func GetCounter() int { return counter } +func Inc() int { counter += 1; return counter } +func pvEcho(msg string) string { return "pvecho:"+msg } +`}, + } + pkgPath := "gno.land/r/hello" + msg1 := NewMsgAddPackage(addr, pkgPath, files) + err := env.vmk.AddPackage(ctx, msg1) + assert.NoError(t, err) + + req := abci.RequestQuery{ + Path: "vm/qfuncs", + Data: tc.input, + } + + res := vmHandler.Query(env.ctx, req) + if tc.expectedErrorMatch == "" { + assert.True(t, res.IsOK(), "should not have error") + if tc.expectedResult != "" { + assert.Equal(t, string(res.Data), tc.expectedResult) + } + } else { + assert.False(t, res.IsOK(), "should have an error") + errmsg := res.Error.Error() + assert.Regexp(t, tc.expectedErrorMatch, errmsg) + } + }) + } +} + +func TestVmHandlerQuery_File(t *testing.T) { + tt := []struct { + input []byte + expectedResult string + expectedResultMatch string + expectedErrorMatch string + expectedPanicMatch string + // XXX: expectedEvents + }{ + // valid queries + {input: []byte(`gno.land/r/hello/hello.gno`), expectedResult: "package hello\n\nfunc Hello() string { return \"hello\" }\n"}, + {input: []byte(`gno.land/r/hello/README.md`), expectedResult: "# Hello"}, + {input: []byte(`gno.land/r/hello/doesnotexist.gno`), expectedErrorMatch: `file "gno.land/r/hello/doesnotexist.gno" is not available`}, + {input: []byte(`gno.land/r/hello`), expectedResult: "README.md\nhello.gno"}, + {input: []byte(`gno.land/r/doesnotexist`), expectedErrorMatch: `package "gno.land/r/doesnotexist" is not available`}, + {input: []byte(`gno.land/r/doesnotexist/hello.gno`), expectedErrorMatch: `file "gno.land/r/doesnotexist/hello.gno" is not available`}, + } + + for _, tc := range tt { + name := string(tc.input) + t.Run(name, func(t *testing.T) { + env := setupTestEnv() + ctx := env.vmk.MakeGnoTransactionStore(env.ctx) + vmHandler := env.vmh + + // 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("10000000ugnot")) + assert.True(t, env.bank.GetCoins(ctx, addr).IsEqual(std.MustParseCoins("10000000ugnot"))) + + // Create test package. + files := []*gnovm.MemFile{ + {"README.md", "# Hello"}, + {"hello.gno", "package hello\n\nfunc Hello() string { return \"hello\" }\n"}, + } + pkgPath := "gno.land/r/hello" + msg1 := NewMsgAddPackage(addr, pkgPath, files) + err := env.vmk.AddPackage(ctx, msg1) + assert.NoError(t, err) + + req := abci.RequestQuery{ + Path: "vm/qfile", + Data: tc.input, + } + + defer func() { + if r := recover(); r != nil { + output := fmt.Sprintf("%v", r) + assert.Regexp(t, tc.expectedPanicMatch, output) + } else { + assert.Equal(t, "", tc.expectedPanicMatch, "should not panic") + } + }() + res := vmHandler.Query(env.ctx, req) + if tc.expectedErrorMatch == "" { + assert.True(t, res.IsOK(), "should not have error") + if tc.expectedResult != "" { + assert.Equal(t, string(res.Data), tc.expectedResult) + } + if tc.expectedResultMatch != "" { + assert.Regexp(t, tc.expectedResultMatch, string(res.Data)) + } + } else { + assert.False(t, res.IsOK(), "should have an error") + errmsg := res.Error.Error() + assert.Regexp(t, tc.expectedErrorMatch, errmsg) + } + }) + } +} From 8ec556e603ed5c21796409b5b487cbf9bf28751f Mon Sep 17 00:00:00 2001 From: 6h057 <15034695+omarsy@users.noreply.github.com> Date: Wed, 30 Oct 2024 22:56:47 +0100 Subject: [PATCH 62/64] fix(gnovm): forbid star expression when value is nil (#3053) close: #3052
Contributors' checklist... - [ ] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [ ] Updated the official documentation or not needed - [ ] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests
--- gnovm/pkg/gnolang/preprocess.go | 3 +++ gnovm/tests/files/ptr10.gno | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 gnovm/tests/files/ptr10.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 10c55979520..a7a1e15bbf3 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1760,6 +1760,9 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *StarExpr: xt := evalStaticTypeOf(store, last, n.X) + if xt == nil { + panic(fmt.Sprintf("invalid operation: cannot indirect nil")) + } if xt.Kind() != PointerKind && xt.Kind() != TypeKind { panic(fmt.Sprintf("invalid operation: cannot indirect %s (variable of type %s)", n.X.String(), xt.String())) } diff --git a/gnovm/tests/files/ptr10.gno b/gnovm/tests/files/ptr10.gno new file mode 100644 index 00000000000..807fc149808 --- /dev/null +++ b/gnovm/tests/files/ptr10.gno @@ -0,0 +1,8 @@ +package main + +func main() { + println(*nil) +} + +// Error: +// main/files/ptr10.gno:4:10: invalid operation: cannot indirect nil From 287335461efc8857b8a56ab0d9749bc3c6244fdd Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:12:41 +0100 Subject: [PATCH 63/64] test(gnovm): indented json on filetests's Events: directives (#3055) Closer to the current `// Realm:` output, and more git-friendly. Bigger example in #3003. Signed-off-by: moul <94029+moul@users.noreply.github.com> --- .../gno.land/r/demo/event/z1_filetest.gno | 25 ++++++++++++++++++- .../testdata/gno_test/filetest_events.txtar | 20 ++++++++++++++- gnovm/tests/file.go | 2 +- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/r/demo/event/z1_filetest.gno b/examples/gno.land/r/demo/event/z1_filetest.gno index 1fcfa1a0e4f..b138aa4351c 100644 --- a/examples/gno.land/r/demo/event/z1_filetest.gno +++ b/examples/gno.land/r/demo/event/z1_filetest.gno @@ -8,4 +8,27 @@ func main() { } // Events: -// [{"type":"TAG","attrs":[{"key":"key","value":"foo"}],"pkg_path":"gno.land/r/demo/event","func":"Emit"},{"type":"TAG","attrs":[{"key":"key","value":"bar"}],"pkg_path":"gno.land/r/demo/event","func":"Emit"}] +// [ +// { +// "type": "TAG", +// "attrs": [ +// { +// "key": "key", +// "value": "foo" +// } +// ], +// "pkg_path": "gno.land/r/demo/event", +// "func": "Emit" +// }, +// { +// "type": "TAG", +// "attrs": [ +// { +// "key": "key", +// "value": "bar" +// } +// ], +// "pkg_path": "gno.land/r/demo/event", +// "func": "Emit" +// } +// ] diff --git a/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar b/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar index 5e0520a2e85..0236872e78a 100644 --- a/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar @@ -30,4 +30,22 @@ func main() { // test // Events: -// [{"type":"EventA","attrs":[],"pkg_path":"","func":"main"},{"type":"EventB","attrs":[{"key":"keyA","value":"valA"}],"pkg_path":"","func":"main"}] +// [ +// { +// "type": "EventA", +// "attrs": [], +// "pkg_path": "", +// "func": "main" +// }, +// { +// "type": "EventB", +// "attrs": [ +// { +// "key": "keyA", +// "value": "valA" +// } +// ], +// "pkg_path": "", +// "func": "main" +// } +// ] diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go index 9df982d4fd8..98e54114af9 100644 --- a/gnovm/tests/file.go +++ b/gnovm/tests/file.go @@ -374,7 +374,7 @@ func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { } // check result events := m.Context.(*teststd.TestExecContext).EventLogger.Events() - evtjson, err := json.Marshal(events) + evtjson, err := json.MarshalIndent(events, "", " ") if err != nil { panic(err) } From af057801de3657c5910101b14b7996591f31cec6 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Thu, 31 Oct 2024 18:50:05 +0100 Subject: [PATCH 64/64] ci: publish master Docker images without `--snapshot` flag (#3057) --- .github/workflows/releaser-master.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/releaser-master.yml b/.github/workflows/releaser-master.yml index 535cac5d965..7f81ef1ad1a 100644 --- a/.github/workflows/releaser-master.yml +++ b/.github/workflows/releaser-master.yml @@ -18,6 +18,8 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Create a dummy tag to avoid goreleaser failure + run: git tag v0.0.0 master - uses: actions/setup-go@v5 with: @@ -40,7 +42,7 @@ jobs: with: distribution: goreleaser-pro version: ~> v2 - args: release --clean --snapshot --nightly --config ./.github/goreleaser.yaml + args: release --clean --nightly --config ./.github/goreleaser.yaml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}