[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: \"\\U0001F41E Bug report\"\ndescription: Report an issue with IBAX\nlabels: [pending triage]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: textarea\n    id: bug-description\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!\n      placeholder: Bug description\n    validations:\n      required: true\n  - type: textarea\n    id: reproduction\n    attributes:\n      label: Reproduction\n      description: Please provide a link to a repo that can reproduce the problem you ran into. A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is required unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a \"need reproduction\" label. If no reproduction is provided after 3 days, it will be auto-closed.\n      placeholder: Reproduction\n    validations:\n      required: true\n  - type: textarea\n    id: system-info\n    attributes:\n      label: System Info\n      description: \n      render: shell\n      placeholder: System, Binaries, Browsers\n    validations:\n      required: true\n  - type: textarea\n    id: logs\n    attributes:\n      label: Logs\n      description: |\n        Optional if provided reproduction. Please try not to insert an image but copy paste the log text.\n\n        1. Run `go-ibax` or `go-ibax start` with the `--test` flag.\n        2. Provide the error log here.\n      render: shell\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: Read the [docs](https://docs.ibax.io).\n          required: true\n        - label: Check that there isn't [already an issue](https://github.com/IBAX-io/go-ibax/issues) that reports the same bug to avoid creating a duplicate.\n          required: true\n        - label: Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/IBAX-io/go-ibax/discussions) or join our [Discord Chat Server](https://discord.com/invite/zRX6Mwafya).\n          required: true\n        - label: The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: IBAX Official English Group\n    url: https://t.me/IBAXNetwork\n    about: A Decentralized Commercial Cross-Chain infrastructure Network.\n  - name: Discord Chat\n    url: https://discord.com/invite/zRX6Mwafya\n    about: Ask questions and discuss with other IBAX users in real time.\n  - name: Questions & Discussions\n    url: https://github.com/IBAX-io/go-ibax/discussions\n    about: Use GitHub discussions for message-board style questions and discussions.\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: \"\\U0001F680 New feature proposal\"\ndescription: Propose a new feature to be added to IBAX\nlabels: [\"enhancement: pending triage\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in the project and taking the time to fill out this feature report!\n  - type: textarea\n    id: feature-description\n    attributes:\n      label: Clear and concise description of the problem\n      description: \"As a developer using IBAX I want [goal / wish] so that [benefit]. If you intend to submit a PR for this issue, tell us in the description. Thanks!\"\n    validations:\n      required: true\n  - type: textarea\n    id: suggested-solution\n    attributes:\n      label: Suggested solution\n      description: \"In module [xy] we could provide following implementation...\"\n    validations:\n      required: true\n  - type: textarea\n    id: alternative\n    attributes:\n      label: Alternative\n      description: Clear and concise description of any alternative solutions or features you've considered.\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional context\n      description: Any other context or screenshots about the feature request here.\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: Read the [docs](https://docs.ibax.io).\n          required: true\n        - label: Check that there isn't already an issue that request the same feature to avoid creating a duplicate.\n          required: true\n"
  },
  {
    "path": ".gitignore",
    "content": ".directory\n\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n# User-specific stuff:\n# .idea/workspace.xml\n# .idea/tasks.xml\n# .idea/dictionaries\n\n# Sensitive or high-churn files:\n# .idea/dataSources.ids\n# .idea/dataSources.xml\n# .idea/sqlDataSources.xml\n# .idea/dynamic.xml\n# .idea/uiDesigner.xml\n\n# Gradle:\n# .idea/gradle.xml\n# .idea/libraries\n\n# Mongo Explorer plugin:\n# .idea/mongoSettings.xml\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\n### Go template\n# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n*.ffs_db\n*.exe\n*.test\n*.prof\n### OSX template\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n\npackages/api/key\ngo-ibax\n1block\nNodePrivateKey\nPrivateKey\nNodePublicKey\nPublicKey\nKeyID\nchain.pid\nconfig.toml\n\npackages/static/\npublic/\n\n.vscode/\n\npackages/api/helper_test.go\n/tempdir/*\n#/tools/\n.scannerwork/\nsonar-project.properties\ntempdir/\nibax-log/\npackages/api/key*\n*.lock\n*.pid\ninitDatabase.txt\n.env\ndocker-compose.yml\nDockerfile\nDockerfile_src\ntest.log\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: go\n\nenv: GO111MODULE=on\n\ngo:\n  - 1.17.x\n  - master\n\ngo_import_path: github.com/IBAX-io/go-ibax\n\ninstall: true\n\nscript: go build github.com/IBAX-io/go-ibax\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 IBAX.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "Makefile",
    "content": "export GOPROXY=https://goproxy.io\nexport GO111MODULE=on\n\nHOMEDIR := $(shell pwd)\n\nall: mod build\n\nmod:\n\tgo mod tidy -v\n\nbuild:\n\tbash $(HOMEDIR)/build.sh\n\ntry:\n\tgo build\n\tgo-ibax generateFirstBlock --test=true\n\tgo-ibax initDatabase\n\tgo-ibax start\n\ninit:\n\tgo-ibax initDatabase\n\n# avoid filename conflict and speed up build\n.PHONY: all\n"
  },
  {
    "path": "README.md",
    "content": "# IBAX Blockchain System Platform\r\n\r\n[![Go Reference](https://pkg.go.dev/badge/github.com/IBAX-io/go-ibax.svg)](https://pkg.go.dev/github.com/IBAX-io/go-ibax)\r\n[![Go Report Card](https://goreportcard.com/badge/github.com/IBAX-io/go-ibax)](https://goreportcard.com/report/github.com/IBAX-io/go-ibax)\r\n\r\n## The Most Powerful Infrastructure for Applications on Decentralized/Centralized Ecosystems\r\n\r\nA powerful blockchain system platform with a new system framework and a simplified programming language, it is including\r\nsmart contract, database table and interface.\r\n\r\n### Build from Source\r\n\r\n#### Install Go\r\n\r\nThe build process for go-ibax requires Go 1.17 or higher. If you don't have it: [Download Go 1.17+](https://go.dev).\r\n\r\nYou'll need to add Go's bin directories to your `$PATH` environment variable e.g., by adding these lines to\r\nyour `/etc/profile` (for a system-wide installation) or `$HOME/.profile`:\r\n\r\n```\r\nexport PATH=$PATH:/usr/local/go/bin\r\nexport PATH=$PATH:$GOPATH/bin\r\n```\r\n\r\n(If you run into trouble, see the [Go install instructions](https://go.dev/dl/)).\r\n\r\n#### Compile\r\n\r\n```\r\n$ export GOPROXY=https://athens.azurefd.net\r\n$ GO111MODULE=on go mod tidy -v\r\n\r\n$ go build\r\n```\r\n\r\n### Run\r\n\r\n1. Create the node configuration file:\r\n\r\n```bash\r\n$    go-ibax config\r\n```\r\n\r\n2. Generate node keys:\r\n\r\n```bash\r\n$    go-ibax generateKeys\r\n```\r\n\r\n3. Generate the first block. If you are creating your own blockchain network. You must use the `--test=true` option.\r\n   Otherwise you will not be able to create new accounts.\r\n\r\n```bash\r\n$    go-ibax generateFirstBlock --test=true\r\n```\r\n\r\n4. Initialize the database.\r\n\r\n```bash\r\n$    go-ibax initDatabase\r\n```\r\n\r\n5.Starting go-ibax.\r\n\r\n```bash\r\n$    go-ibax start\r\n```\r\n\r\n\r\n\r\n"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\nset -e -x\n\nHOMEDIR=$(pwd)\n\nfunction buildpkg() {\n    buildBin=$1\n    buildModule=$2\n    buildFile=$3\n    buildBranch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)\n    buildDate=$(date -u \"+%Y-%m-%d-%H:%M:%S(UTC)\")\n    commitHash=$(git rev-parse --short HEAD 2>/dev/null || echo unknown)\n    go build -o \"$buildBin\" -ldflags \"-s -w -X $buildModule/cmd.buildBranch=$buildBranch -X $buildModule/cmd.buildDate=$buildDate -X $buildModule/cmd.commitHash=$commitHash\" \"$buildFile\"\n}\n\nbuildpkg go-ibax \"github.com/IBAX-io/go-ibax\" \"$HOMEDIR/main.go\"\n"
  },
  {
    "path": "cmd/config.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\n// configCmd represents the config command\nvar configCmd = &cobra.Command{\n\tUse:   \"config\",\n\tShort: \"Initial config generation\",\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\t// Error omitted because we have default flag value\n\t\tconfigPath, _ := cmd.Flags().GetString(\"path\")\n\n\t\terr := conf.FillRuntimePaths()\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatal(\"Filling config\")\n\t\t}\n\n\t\tif configPath == \"\" {\n\t\t\tconfigPath = filepath.Join(conf.Config.DirPathConf.DataDir, consts.DefaultConfigFile)\n\t\t}\n\t\terr = viper.Unmarshal(&conf.Config)\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatal(\"Marshalling config to global struct variable\")\n\t\t}\n\n\t\terr = conf.SaveConfig(configPath)\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatal(\"Saving config\")\n\t\t}\n\t\tlog.Infof(\"Config is saved to %s\", configPath)\n\t},\n}\n\nfunc init() {\n\n\tcmdFlags := configCmd.Flags()\n\t// Command flags\n\tcmdFlags.String(\"path\", \"\", \"Generate config to (default dataDir/config.toml)\")\n\n\t// Etc\n\tcmdFlags.StringVar(&conf.Config.DirPathConf.PidFilePath, \"pid\", \"\",\n\t\tfmt.Sprintf(\"ibax pid file name (default dataDir/%s)\", consts.DefaultPidFilename),\n\t)\n\tcmdFlags.StringVar(&conf.Config.DirPathConf.LockFilePath, \"lock\", \"\",\n\t\tfmt.Sprintf(\"ibax lock file name (default dataDir/%s)\", consts.DefaultLockFilename),\n\t)\n\tcmdFlags.StringVar(&conf.Config.DirPathConf.KeysDir, \"keysDir\", \"\", \"Keys directory (default dataDir)\")\n\tcmdFlags.StringVar(&conf.Config.DirPathConf.DataDir, \"dataDir\", \"\", \"Data directory (default cwd/data)\")\n\tcmdFlags.StringVar(&conf.Config.DirPathConf.TempDir, \"tempDir\", \"\", \"Temporary directory (default temporary directory of OS)\")\n\tcmdFlags.StringVar(&conf.Config.DirPathConf.FirstBlockPath, \"firstBlock\", \"\", \"First block path (default dataDir/1block)\")\n\n\t// tls\n\tcmdFlags.BoolVar(&conf.Config.TLSConf.Enabled, \"tlsEnable\", false, \"Enable https\")\n\tcmdFlags.StringVar(&conf.Config.TLSConf.TLSCert, \"tlsCert\", \"\", \"Filepath to the fullchain of certificates\")\n\tcmdFlags.StringVar(&conf.Config.TLSConf.TLSKey, \"tlsKey\", \"\", \"Filepath to the private key\")\n\n\t//Bootstrap\n\tcmdFlags.StringSliceVar(&conf.Config.BootNodes.NodesAddr, \"bootNodes\", []string{}, \"List of addresses for downloading blockchain\")\n\n\t//LocalConf\n\tcmdFlags.Int64Var(&conf.Config.LocalConf.MaxPageGenerationTime, \"mpgt\", 3000, \"Max page generation time in ms\")\n\tcmdFlags.Int64Var(&conf.Config.LocalConf.HTTPServerMaxBodySize, \"mbs\", 1<<20, \"Max server body size in byte\")\n\tcmdFlags.Int64Var(&conf.Config.LocalConf.NetworkID, \"networkID\", 1, \"Network ID\")\n\tcmdFlags.StringVar(&conf.Config.LocalConf.RunNodeMode, \"runMode\", consts.NoneCLB, \"running node mode, example NONE|CLB|CLBMaster|SubNode\")\n\n\t// TCP Server\n\tcmdFlags.StringVar(&conf.Config.TCPServer.Host, \"tcpHost\", \"127.0.0.1\", \"Node TCP host\")\n\tcmdFlags.IntVar(&conf.Config.TCPServer.Port, \"tcpPort\", 7078, \"Node TCP port\")\n\n\t// HTTP Server\n\tcmdFlags.StringVar(&conf.Config.HTTP.Host, \"httpHost\", \"127.0.0.1\", \"Node HTTP host\")\n\tcmdFlags.IntVar(&conf.Config.HTTP.Port, \"httpPort\", 7079, \"Node HTTP port\")\n\n\t// JSON-RPC Server\n\tcmdFlags.BoolVar(&conf.Config.JsonRPC.Enabled, \"jsonRPCEnabled\", false, \"Node Json-RPC Enabled\")\n\tcmdFlags.StringVar(&conf.Config.JsonRPC.Namespace, \"jsonRPCNamespace\", \"ibax,net\", \"Node Json-RPC Namespace\")\n\n\t// DB\n\tcmdFlags.StringVar(&conf.Config.DB.Host, \"dbHost\", \"127.0.0.1\", \"DB host\")\n\tcmdFlags.IntVar(&conf.Config.DB.Port, \"dbPort\", 5432, \"DB port\")\n\tcmdFlags.StringVar(&conf.Config.DB.Name, \"dbName\", \"ibax\", \"DB name\")\n\tcmdFlags.StringVar(&conf.Config.DB.User, \"dbUser\", \"postgres\", \"DB username\")\n\tcmdFlags.StringVar(&conf.Config.DB.Password, \"dbPassword\", \"123456\", \"DB password\")\n\tcmdFlags.IntVar(&conf.Config.DB.LockTimeout, \"dbLockTimeout\", 5000, \"DB lock timeout\")\n\tcmdFlags.IntVar(&conf.Config.DB.IdleInTxTimeout, \"dbIdleInTxTimeout\", 5000, \"DB idle tx timeout\")\n\tcmdFlags.IntVar(&conf.Config.DB.MaxIdleConns, \"dbMaxIdleConns\", 5, \"DB sets the maximum number of connections in the idle connection pool\")\n\tcmdFlags.IntVar(&conf.Config.DB.MaxOpenConns, \"dbMaxOpenConns\", 100, \"sets the maximum number of open connections to the database\")\n\n\t//Redis\n\tcmdFlags.BoolVar(&conf.Config.Redis.Enable, \"redisEnable\", false, \"enable redis\")\n\tcmdFlags.StringVar(&conf.Config.Redis.Host, \"redisHost\", \"localhost\", \"redis host\")\n\tcmdFlags.IntVar(&conf.Config.Redis.Port, \"redisPort\", 6379, \"redis port\")\n\tcmdFlags.IntVar(&conf.Config.Redis.DbName, \"redisDb\", 0, \"redis db\")\n\tcmdFlags.StringVar(&conf.Config.Redis.Password, \"redisPassword\", \"123456\", \"redis password\")\n\n\t// StatsD\n\tcmdFlags.StringVar(&conf.Config.StatsD.Host, \"statsdHost\", \"127.0.0.1\", \"StatsD host\")\n\tcmdFlags.IntVar(&conf.Config.StatsD.Port, \"statsdPort\", 8125, \"StatsD port\")\n\tcmdFlags.StringVar(&conf.Config.StatsD.Name, \"statsdName\", \"chain\", \"StatsD name\")\n\n\t// Centrifugo\n\tcmdFlags.StringVar(&conf.Config.Centrifugo.Secret, \"centSecret\", \"127.0.0.1\", \"Centrifugo secret\")\n\tcmdFlags.StringVar(&conf.Config.Centrifugo.URL, \"centUrl\", \"127.0.0.1\", \"Centrifugo URL\")\n\tcmdFlags.StringVar(&conf.Config.Centrifugo.Key, \"centKey\", \"127.0.0.1\", \"Centrifugo API key\")\n\n\t// Log\n\tcmdFlags.StringVar(&conf.Config.Log.LogTo, \"logTo\", \"stdout\", \"Send logs to stdout|(filename)|syslog\")\n\tcmdFlags.StringVar(&conf.Config.Log.LogLevel, \"logLevel\", \"ERROR\", \"Log verbosity (DEBUG | INFO | WARN | ERROR)\")\n\tcmdFlags.StringVar(&conf.Config.Log.LogFormat, \"logFormat\", \"text\", \"log format, could be text|json\")\n\tcmdFlags.StringVar(&conf.Config.Log.Syslog.Facility, \"syslogFacility\", \"kern\", \"syslog facility\")\n\tcmdFlags.StringVar(&conf.Config.Log.Syslog.Tag, \"syslogTag\", \"go-ibax\", \"syslog program tag\")\n\n\t// TokenMovement\n\tcmdFlags.StringVar(&conf.Config.TokenMovement.Host, \"tmovHost\", \"\", \"Token movement host\")\n\tcmdFlags.IntVar(&conf.Config.TokenMovement.Port, \"tmovPort\", 0, \"Token movement port\")\n\tcmdFlags.StringVar(&conf.Config.TokenMovement.Username, \"tmovUser\", \"\", \"Token movement username\")\n\tcmdFlags.StringVar(&conf.Config.TokenMovement.Password, \"tmovPw\", \"\", \"Token movement password\")\n\tcmdFlags.StringVar(&conf.Config.TokenMovement.To, \"tmovTo\", \"\", \"Token movement to field\")\n\tcmdFlags.StringVar(&conf.Config.TokenMovement.From, \"tmovFrom\", \"\", \"Token movement from field\")\n\tcmdFlags.StringVar(&conf.Config.TokenMovement.Subject, \"tmovSubj\", \"\", \"Token movement subject\")\n\n\tcmdFlags.IntVar(&conf.Config.BanKey.BadTime, \"badTime\", 5, \"Period for bad tx (minutes)\")\n\tcmdFlags.IntVar(&conf.Config.BanKey.BanTime, \"banTime\", 15, \"Ban time in minutes\")\n\tcmdFlags.IntVar(&conf.Config.BanKey.BadTx, \"badTx\", 5, \"Maximum bad tx during badTime minutes\")\n\n\t// CryptoSettings\n\tcmdFlags.StringVar(&conf.Config.CryptoSettings.Hasher, \"hasher\", crypto.HashAlgo_KECCAK256.String(), fmt.Sprintf(\"Hash Algorithm (%s | %s | %s | %s)\", crypto.HashAlgo_SHA256, crypto.HashAlgo_KECCAK256, crypto.HashAlgo_SHA3_256, crypto.HashAlgo_SM3))\n\tcmdFlags.StringVar(&conf.Config.CryptoSettings.Cryptoer, \"cryptoer\", crypto.AsymAlgo_ECC_Secp256k1.String(), fmt.Sprintf(\"Key and Sign Algorithm (%s | %s | %s | %s)\", crypto.AsymAlgo_ECC_P256, crypto.AsymAlgo_ECC_Secp256k1, crypto.AsymAlgo_ECC_P512, crypto.AsymAlgo_SM2))\n\n\t// BlockSyncMethod\n\tcmdFlags.StringVar(&conf.Config.BlockSyncMethod.Method, \"sync\", types.BlockSyncMethod_CONTRACTVM.String(), fmt.Sprintf(\"Block sync method (%s | %s)\", types.BlockSyncMethod_CONTRACTVM, types.BlockSyncMethod_SQLDML))\n\n\tviper.BindPFlags(configCmd.PersistentFlags())\n}\n"
  },
  {
    "path": "cmd/generateFirstBlock.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar stopNetworkBundleFilepath string\nvar testBlockchain bool\nvar privateBlockchain bool\n\n// generateFirstBlockCmd represents the generateFirstBlock command\nvar generateFirstBlockCmd = &cobra.Command{\n\tUse:    \"generateFirstBlock\",\n\tShort:  \"First generation\",\n\tPreRun: loadConfigWKey,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tblock, err := genesisBlock()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.MarshallingError, \"error\": err}).Fatal(\"first block marshalling\")\n\t\t}\n\t\tos.WriteFile(conf.Config.DirPathConf.FirstBlockPath, block, 0644)\n\t\tlog.Info(\"first block generated\")\n\t},\n}\n\nfunc init() {\n\tgenerateFirstBlockCmd.Flags().StringVar(&stopNetworkBundleFilepath, \"stopNetworkCert\", \"\", \"Filepath to the fullchain of certificates for network stopping\")\n\tgenerateFirstBlockCmd.Flags().BoolVar(&testBlockchain, \"test\", false, \"if true - test blockchain\")\n\tgenerateFirstBlockCmd.Flags().BoolVar(&privateBlockchain, \"private\", false, \"if true - all transactions will be free\")\n}\n\nfunc genesisBlock() ([]byte, error) {\n\tnow := time.Now().Unix()\n\theader := &types.BlockHeader{\n\t\tBlockId:       1,\n\t\tTimestamp:     now,\n\t\tEcosystemId:   0,\n\t\tKeyId:         conf.Config.KeyID,\n\t\tNetworkId:     conf.Config.LocalConf.NetworkID,\n\t\tNodePosition:  0,\n\t\tVersion:       consts.BlockVersion,\n\t\tRollbacksHash: crypto.Hash([]byte(`0`)),\n\t\tConsensusMode: consts.HonorNodeMode,\n\t}\n\tdecodeKeyFile := func(kName string) []byte {\n\t\tfilepath := filepath.Join(conf.Config.DirPathConf.KeysDir, kName)\n\t\tdata, err := os.ReadFile(filepath)\n\t\tif err != nil {\n\t\t\tlog.WithError(err).WithFields(log.Fields{\"key\": kName, \"filepath\": filepath}).Fatal(\"Reading key data\")\n\t\t}\n\n\t\tdecodedKey, err := crypto.HexToPub(string(data))\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatalf(\"converting %s from hex\", kName)\n\t\t}\n\n\t\treturn decodedKey\n\t}\n\n\tvar stopNetworkCert []byte\n\tif len(stopNetworkBundleFilepath) > 0 {\n\t\tvar err error\n\t\tfp := filepath.Join(conf.Config.DirPathConf.KeysDir, stopNetworkBundleFilepath)\n\t\tif stopNetworkCert, err = os.ReadFile(fp); err != nil {\n\t\t\tlog.WithError(err).WithFields(log.Fields{\"filepath\": fp}).Fatal(\"Reading cert data\")\n\t\t}\n\t}\n\n\tif len(stopNetworkCert) == 0 {\n\t\tlog.Warn(\"the fullchain of certificates for a network stopping is not specified\")\n\t}\n\n\tvar test int64\n\tvar pb uint64\n\tif testBlockchain == true {\n\t\ttest = 1\n\t}\n\tif privateBlockchain == true {\n\t\tpb = 1\n\t}\n\n\tfbp := new(transaction.FirstBlockParser)\n\ttx, err := fbp.BinMarshal(&types.FirstBlock{\n\t\tKeyID:                 conf.Config.KeyID,\n\t\tTime:                  now,\n\t\tPublicKey:             decodeKeyFile(consts.PublicKeyFilename),\n\t\tNodePublicKey:         decodeKeyFile(consts.NodePublicKeyFilename),\n\t\tStopNetworkCertBundle: stopNetworkCert,\n\t\tTest:                  test,\n\t\tPrivateBlockchain:     pb,\n\t})\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.MarshallingError, \"error\": err}).Fatal(\"first block body bin marshalling\")\n\t}\n\treturn block.MarshallBlock(types.WithCurHeader(header),\n\t\ttypes.WithPrevHeader(&types.BlockHeader{\n\t\t\tBlockHash:     crypto.DoubleHash([]byte(`0`)),\n\t\t\tRollbacksHash: crypto.Hash([]byte(`0`)),\n\t\t}), types.WithTxFullData([][]byte{tx}))\n}\n"
  },
  {
    "path": "cmd/generateKeys.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"encoding/hex\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n)\n\nconst fileMode = 0600\n\n// generateKeysCmd represents the generateKeys command\nvar generateKeysCmd = &cobra.Command{\n\tUse:    \"generateKeys\",\n\tShort:  \"Keys generation\",\n\tPreRun: loadConfig,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\t_, publicKey, err := createKeyPair(\n\t\t\tfilepath.Join(conf.Config.DirPathConf.KeysDir, consts.PrivateKeyFilename),\n\t\t\tfilepath.Join(conf.Config.DirPathConf.KeysDir, consts.PublicKeyFilename),\n\t\t)\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatal(\"generating user keys\")\n\t\t\treturn\n\t\t}\n\t\t_, _, err = createKeyPair(\n\t\t\tfilepath.Join(conf.Config.DirPathConf.KeysDir, consts.NodePrivateKeyFilename),\n\t\t\tfilepath.Join(conf.Config.DirPathConf.KeysDir, consts.NodePublicKeyFilename),\n\t\t)\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatal(\"generating node keys\")\n\t\t\treturn\n\t\t}\n\t\taddress := crypto.Address(publicKey)\n\t\tkeyIDPath := filepath.Join(conf.Config.DirPathConf.KeysDir, consts.KeyIDFilename)\n\t\terr = createFile(keyIDPath, []byte(strconv.FormatInt(address, 10)))\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"path\": keyIDPath}).Fatal(\"generating node keys\")\n\t\t\treturn\n\t\t}\n\t\tlog.Info(\"keys generated\")\n\t},\n}\n\nfunc createFile(filename string, data []byte) error {\n\tdir := filepath.Dir(filename)\n\tif _, err := os.Stat(dir); os.IsNotExist(err) {\n\t\terr := os.Mkdir(dir, 0775)\n\t\tif err != nil {\n\t\t\treturn errors.Wrapf(err, \"creating dir %s\", dir)\n\t\t}\n\t}\n\n\treturn os.WriteFile(filename, data, fileMode)\n}\n\nfunc createKeyPair(privFilename, pubFilename string) (priv, pub []byte, err error) {\n\tpriv, pub, err = crypto.GenKeyPair()\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"generate keys\")\n\t\treturn\n\t}\n\n\terr = createFile(privFilename, []byte(hex.EncodeToString(priv)))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"path\": privFilename}).Error(\"creating private key\")\n\t\treturn\n\t}\n\n\terr = createFile(pubFilename, []byte(crypto.PubToHex(pub)))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"path\": pubFilename}).Error(\"creating public key\")\n\t\treturn\n\t}\n\treturn\n}\n"
  },
  {
    "path": "cmd/initDatabase.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\n// initDatabaseCmd represents the initDatabase command\nvar initDatabaseCmd = &cobra.Command{\n\tUse:    \"initDatabase\",\n\tShort:  \"Initializing database\",\n\tPreRun: loadConfigWKey,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif err := sqldb.InitDB(conf.Config.DB); err != nil {\n\t\t\tlog.WithError(err).Fatal(\"init db\")\n\t\t}\n\t\tlog.Info(\"initDatabase completed\")\n\t},\n}\n"
  },
  {
    "path": "cmd/rollback.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/rollback\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar blockID int64\n\n// rollbackCmd represents the rollback command\nvar rollbackCmd = &cobra.Command{\n\tUse:    \"rollback\",\n\tShort:  \"Rollback blockchain to blockID\",\n\tPreRun: loadConfigWKey,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tf := utils.LockOrDie(conf.Config.DirPathConf.LockFilePath)\n\t\tdefer f.Unlock()\n\n\t\tif err := sqldb.GormInit(conf.Config.DB); err != nil {\n\t\t\tlog.WithError(err).Fatal(\"init db\")\n\t\t\treturn\n\t\t}\n\t\tif err := syspar.SysUpdate(nil); err != nil {\n\t\t\tlog.WithError(err).Error(\"can't read platform parameters\")\n\t\t}\n\t\tif err := syspar.SysTableColType(nil); err != nil {\n\t\t\tlog.WithError(err).Error(\"updating sys table col type\")\n\t\t}\n\n\t\tsmart.InitVM()\n\t\tif err := smart.LoadContracts(); err != nil {\n\t\t\tlog.WithError(err).Fatal(\"loading contracts\")\n\t\t\treturn\n\t\t}\n\t\terr := rollback.ToBlockID(blockID, nil, log.WithFields(log.Fields{}))\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Fatal(\"rollback to block id\")\n\t\t\treturn\n\t\t}\n\n\t\t// block id = 1, is a special case for full rollback\n\t\tif blockID != 1 {\n\t\t\tlog.Info(\"Not full rollback, finishing work without checking\")\n\t\t\treturn\n\t\t}\n\t},\n}\n\nfunc init() {\n\trollbackCmd.Flags().Int64Var(&blockID, \"blockId\", 1, \"blockID to rollback\")\n\trollbackCmd.MarkFlagRequired(\"blockId\")\n}\n"
  },
  {
    "path": "cmd/root.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\n\t\"path/filepath\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n)\n\nvar (\n\tbuildBranch = \"\"\n\tbuildDate   = \"\"\n\tcommitHash  = \"\"\n)\n\n// rootCmd represents the base command when called without any subcommands\nvar rootCmd = &cobra.Command{\n\tUse:   \"go-ibax\",\n\tShort: \"ibax application\",\n}\n\nfunc init() {\n\trootCmd.AddCommand(\n\t\tgenerateFirstBlockCmd,\n\t\tgenerateKeysCmd,\n\t\tinitDatabaseCmd,\n\t\trollbackCmd,\n\t\tstartCmd,\n\t\tconfigCmd,\n\t\tstopNetworkCmd,\n\t\tversionCmd,\n\t)\n\n\tconsts.BuildInfo = func() string {\n\t\tif buildBranch == \"\" {\n\t\t\treturn fmt.Sprintf(\"branch.%s commit.%s time.%s\", \"unknown\", \"unknown\", \"unknown\")\n\t\t}\n\t\treturn fmt.Sprintf(\"branch.%s commit.%s time.%s\", buildBranch, commitHash, buildDate)\n\t}()\n\t// This flags are visible for all child commands\n\trootCmd.PersistentFlags().StringVar(&conf.Config.ConfigPath, \"config\", defautConfigPath(), \"filepath to config.toml\")\n}\n\n// Execute executes rootCmd command.\n// This is called by main.main(). It only needs to happen once to the rootCmd\nfunc Execute() {\n\tif err := rootCmd.Execute(); err != nil {\n\t\tlog.WithError(err).Fatal(\"Executing root command\")\n\t}\n}\n\nfunc defautConfigPath() string {\n\t//p, err := os.Getwd()\n\t//if err != nil {\n\t//\tlog.WithError(err).Fatal(\"getting cur wd\")\n\t//}\n\t//\n\t//return filepath.Join(p, \"data\", \"config.toml\")\n\treturn filepath.Join(\"data\", \"config.toml\")\n}\n\n// Load the configuration from file\nfunc loadConfig(cmd *cobra.Command, args []string) {\n\terr := conf.LoadConfig(conf.Config.ConfigPath)\n\tif err != nil {\n\t\tlog.WithError(err).Fatal(\"Loading config\")\n\t}\n}\n\nfunc loadConfigWKey(cmd *cobra.Command, args []string) {\n\tloadConfig(cmd, args)\n\terr := conf.FillRuntimeKey()\n\tif err != nil {\n\t\tlog.WithError(err).Fatal(\"Filling keys\")\n\t}\n}\n"
  },
  {
    "path": "cmd/start.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/chain\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// startCmd is starting node\nvar startCmd = &cobra.Command{\n\tUse:    \"start\",\n\tShort:  \"Starting node\",\n\tPreRun: loadConfigWKey,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tchain.Start()\n\t},\n}\n\nfunc init() {\n\ttime.Local = time.UTC\n\tstartCmd.Flags().BoolVar(&conf.Config.TestRollBack, \"testRollBack\", false, \"Starts special set of daemons\")\n\tstartCmd.Flags().BoolVar(&conf.Config.FuncBench, \"funcBench\", false, \"Disable access checking in some built-in functions for benchmarks\")\n}\n"
  },
  {
    "path": "cmd/stopNetwork.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\taddrsForStopping        []string\n\tstopNetworkCertFilepath string\n)\n\n// stopNetworkCmd represents the stopNetworkCmd command\nvar stopNetworkCmd = &cobra.Command{\n\tUse:    \"stopNetwork\",\n\tShort:  \"Sending a special transaction to stop the network\",\n\tPreRun: loadConfigWKey,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tfp := filepath.Join(conf.Config.DirPathConf.KeysDir, stopNetworkCertFilepath)\n\t\tstopNetworkCert, err := os.ReadFile(fp)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"filepath\": fp}).Fatal(\"Reading cert data\")\n\t\t}\n\n\t\treq := &network.StopNetworkRequest{\n\t\t\tData: stopNetworkCert,\n\t\t}\n\n\t\terrCount := 0\n\t\tfor _, addr := range addrsForStopping {\n\t\t\tif err := tcpclient.SendStopNetwork(addr, req); err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.NetworkError, \"addr\": addr}).Errorf(\"Sending request\")\n\t\t\t\terrCount++\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlog.WithFields(log.Fields{\"addr\": addr}).Info(\"Sending request\")\n\t\t}\n\n\t\tlog.WithFields(log.Fields{\n\t\t\t\"successful\": len(addrsForStopping) - errCount,\n\t\t\t\"failed\":     errCount,\n\t\t}).Info(\"Complete\")\n\t},\n}\n\nfunc init() {\n\tstopNetworkCmd.Flags().StringVar(&stopNetworkCertFilepath, \"stopNetworkCert\", \"\", \"Filepath to certificate for network stopping\")\n\tstopNetworkCmd.Flags().StringArrayVar(&addrsForStopping, \"addr\", []string{}, \"Node address\")\n\tstopNetworkCmd.MarkFlagRequired(\"stopNetworkCert\")\n\tstopNetworkCmd.MarkFlagRequired(\"addr\")\n}\n"
  },
  {
    "path": "cmd/version.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// versionCmd represents the version command\nvar versionCmd = &cobra.Command{\n\tUse:   \"version\",\n\tShort: \"Show version\",\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tfmt.Println(consts.Version())\n\t},\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/IBAX-io/go-ibax\n\ngo 1.20\n\nrequire (\n\tgithub.com/360EntSecGroup-Skylar/excelize v1.4.1\n\tgithub.com/BurntSushi/toml v1.3.2\n\tgithub.com/btcsuite/btcd v0.24.2\n\tgithub.com/btcsuite/btcd/btcec/v2 v2.3.4\n\tgithub.com/btcsuite/btcd/btcutil v1.1.6\n\tgithub.com/cactus/go-statsd-client/v5 v5.1.0\n\tgithub.com/centrifugal/gocent v2.2.0+incompatible\n\tgithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0\n\tgithub.com/didip/tollbooth v4.0.2+incompatible\n\tgithub.com/go-redis/redis v6.15.9+incompatible\n\tgithub.com/gobuffalo/fizz v1.14.4\n\tgithub.com/gogo/protobuf v1.3.2\n\tgithub.com/golang-jwt/jwt/v4 v4.5.0\n\tgithub.com/gorilla/handlers v1.5.1\n\tgithub.com/gorilla/mux v1.8.0\n\tgithub.com/gorilla/schema v1.2.0\n\tgithub.com/ochinchina/go-ini v1.0.1\n\tgithub.com/ochinchina/supervisord/config v0.0.0-20230719054037-813956ff6a67\n\tgithub.com/ochinchina/supervisord/process v0.0.0-20230719054037-813956ff6a67\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/robfig/cron/v3 v3.0.1\n\tgithub.com/shopspring/decimal v1.3.1\n\tgithub.com/sirupsen/logrus v1.9.3\n\tgithub.com/spf13/cobra v1.7.0\n\tgithub.com/spf13/viper v1.16.0\n\tgithub.com/stretchr/testify v1.9.0\n\tgithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7\n\tgithub.com/theckman/go-flock v0.8.1\n\tgithub.com/tjfoc/gmsm v1.4.1\n\tgithub.com/vmihailenco/msgpack/v5 v5.3.5\n\tgolang.org/x/crypto v0.23.0\n\tgorm.io/driver/postgres v1.5.2\n\tgorm.io/gorm v1.25.2\n)\n\nrequire (\n\tgithub.com/Masterminds/semver/v3 v3.2.1 // indirect\n\tgithub.com/aymerick/douceur v0.2.0 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect\n\tgithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect\n\tgithub.com/fatih/structs v1.1.0 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.3 // indirect\n\tgithub.com/fsnotify/fsnotify v1.6.0 // indirect\n\tgithub.com/gobuffalo/flect v1.0.2 // indirect\n\tgithub.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect\n\tgithub.com/gobuffalo/helpers v0.6.7 // indirect\n\tgithub.com/gobuffalo/plush/v4 v4.1.19 // indirect\n\tgithub.com/gobuffalo/tags/v3 v3.1.4 // indirect\n\tgithub.com/gobuffalo/validate/v3 v3.3.3 // indirect\n\tgithub.com/gofrs/flock v0.8.1 // indirect\n\tgithub.com/gofrs/uuid v4.4.0+incompatible // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect\n\tgithub.com/gorilla/css v1.0.0 // indirect\n\tgithub.com/gorilla/rpc v1.2.0 // indirect\n\tgithub.com/hashicorp/go-envparse v0.1.0 // indirect\n\tgithub.com/hashicorp/hcl v1.0.0 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/jackc/pgpassfile v1.0.0 // indirect\n\tgithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect\n\tgithub.com/jackc/pgx/v5 v5.4.2 // indirect\n\tgithub.com/jinzhu/inflection v1.0.0 // indirect\n\tgithub.com/jinzhu/now v1.1.5 // indirect\n\tgithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect\n\tgithub.com/magiconair/properties v1.8.7 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect\n\tgithub.com/microcosm-cc/bluemonday v1.0.25 // indirect\n\tgithub.com/mitchellh/mapstructure v1.5.0 // indirect\n\tgithub.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect\n\tgithub.com/ochinchina/filechangemonitor v0.3.1 // indirect\n\tgithub.com/ochinchina/gorilla-xmlrpc v0.0.0-20171012055324-ecf2fe693a2c // indirect\n\tgithub.com/ochinchina/supervisord/events v0.0.0-20230719054037-813956ff6a67 // indirect\n\tgithub.com/ochinchina/supervisord/faults v0.0.0-20230719054037-813956ff6a67 // indirect\n\tgithub.com/ochinchina/supervisord/logger v0.0.0-20230719054037-813956ff6a67 // indirect\n\tgithub.com/ochinchina/supervisord/signals v0.0.0-20230719054037-813956ff6a67 // indirect\n\tgithub.com/ochinchina/supervisord/util v0.0.0-20230719054037-813956ff6a67 // indirect\n\tgithub.com/patrickmn/go-cache v2.1.0+incompatible // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.0.9 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/prometheus/client_golang v1.16.0 // indirect\n\tgithub.com/prometheus/client_model v0.4.0 // indirect\n\tgithub.com/prometheus/common v0.44.0 // indirect\n\tgithub.com/prometheus/procfs v0.11.1 // indirect\n\tgithub.com/rogpeppe/go-charset v0.0.0-20190617161244-0dc95cdf6f31 // indirect\n\tgithub.com/sergi/go-diff v1.3.1 // indirect\n\tgithub.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect\n\tgithub.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect\n\tgithub.com/spf13/afero v1.9.5 // indirect\n\tgithub.com/spf13/cast v1.5.1 // indirect\n\tgithub.com/spf13/jwalterweatherman v1.1.0 // indirect\n\tgithub.com/spf13/pflag v1.0.5 // indirect\n\tgithub.com/stretchr/objx v0.5.2 // indirect\n\tgithub.com/subosito/gotenv v1.4.2 // indirect\n\tgithub.com/vmihailenco/tagparser/v2 v2.0.0 // indirect\n\tgolang.org/x/net v0.24.0 // indirect\n\tgolang.org/x/sync v0.7.0 // indirect\n\tgolang.org/x/sys v0.20.0 // indirect\n\tgolang.org/x/text v0.15.0 // indirect\n\tgolang.org/x/time v0.5.0 // indirect\n\tgoogle.golang.org/protobuf v1.34.2 // indirect\n\tgopkg.in/ini.v1 v1.67.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ncloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks=\ngithub.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=\ngithub.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=\ngithub.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=\ngithub.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=\ngithub.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=\ngithub.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=\ngithub.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=\ngithub.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=\ngithub.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=\ngithub.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY=\ngithub.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA=\ngithub.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=\ngithub.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=\ngithub.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=\ngithub.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A=\ngithub.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE=\ngithub.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00=\ngithub.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=\ngithub.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ=\ngithub.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=\ngithub.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=\ngithub.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=\ngithub.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=\ngithub.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=\ngithub.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=\ngithub.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=\ngithub.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=\ngithub.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=\ngithub.com/cactus/go-statsd-client/v5 v5.1.0 h1:sbbdfIl9PgisjEoXzvXI1lwUKWElngsjJKaZeC021P4=\ngithub.com/cactus/go-statsd-client/v5 v5.1.0/go.mod h1:COEvJ1E+/E2L4q6QE5CkjWPi4eeDw9maJBMIuMPBZbY=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/centrifugal/gocent v2.2.0+incompatible h1:49oQLm1CDojd8vgz2w5RrECgW3Ew+Z5muIQGIggI2Vk=\ngithub.com/centrifugal/gocent v2.2.0+incompatible/go.mod h1:gtbj3+fMApCIcaGmGvk2BinwEauUtGeu8YZPLcedOvQ=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=\ngithub.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=\ngithub.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=\ngithub.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=\ngithub.com/didip/tollbooth v4.0.2+incompatible h1:fVSa33JzSz0hoh2NxpwZtksAzAgd7zjmGO20HCZtF4M=\ngithub.com/didip/tollbooth v4.0.2+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=\ngithub.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=\ngithub.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=\ngithub.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=\ngithub.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=\ngithub.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=\ngithub.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=\ngithub.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gobuffalo/fizz v1.14.4 h1:8uume7joF6niTNWN582IQ2jhGTUoa9g1fiV/tIoGdBs=\ngithub.com/gobuffalo/fizz v1.14.4/go.mod h1:9/2fGNXNeIFOXEEgTPJwiK63e44RjG+Nc4hfMm1ArGM=\ngithub.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=\ngithub.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA=\ngithub.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=\ngithub.com/gobuffalo/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I=\ngithub.com/gobuffalo/github_flavored_markdown v1.1.4 h1:WacrEGPXUDX+BpU1GM/Y0ADgMzESKNWls9hOTG1MHVs=\ngithub.com/gobuffalo/github_flavored_markdown v1.1.4/go.mod h1:Vl9686qrVVQou4GrHRK/KOG3jCZOKLUqV8MMOAYtlso=\ngithub.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8=\ngithub.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA=\ngithub.com/gobuffalo/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg=\ngithub.com/gobuffalo/plush/v4 v4.1.19 h1:o0E5gEJw+ozkAwQoCeiaWC6VOU2lEmX+GhtGkwpqZ8o=\ngithub.com/gobuffalo/plush/v4 v4.1.19/go.mod h1:WiKHJx3qBvfaDVlrv8zT7NCd3dEMaVR/fVxW4wqV17M=\ngithub.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHjsM=\ngithub.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0=\ngithub.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4=\ngithub.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g=\ngithub.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=\ngithub.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=\ngithub.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=\ngithub.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=\ngithub.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=\ngithub.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=\ngithub.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=\ngithub.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=\ngithub.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=\ngithub.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=\ngithub.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=\ngithub.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=\ngithub.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk=\ngithub.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=\ngithub.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=\ngithub.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=\ngithub.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=\ngithub.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=\ngithub.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=\ngithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=\ngithub.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=\ngithub.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg=\ngithub.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=\ngithub.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=\ngithub.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=\ngithub.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=\ngithub.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=\ngithub.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\ngithub.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=\ngithub.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=\ngithub.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=\ngithub.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50=\ngithub.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=\ngithub.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=\ngithub.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=\ngithub.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=\ngithub.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=\ngithub.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/ochinchina/filechangemonitor v0.3.1 h1:Fyt8iE44kFwmI3ncNWAi21GZnmRBrAUSlMunpcDlMjQ=\ngithub.com/ochinchina/filechangemonitor v0.3.1/go.mod h1:OLRTJMpgb3yP1zBKA2g5GMYsKzJUoLq01lNOsReEzbQ=\ngithub.com/ochinchina/go-ini v1.0.1 h1:qrKGrgxJjY+4H8aV7B2HPohShzHGrymW+/X1Gx933zU=\ngithub.com/ochinchina/go-ini v1.0.1/go.mod h1:Tqs5+JmccLSNMX1KXbbyG/B3ro4J9uXVYC5U5VOeRE8=\ngithub.com/ochinchina/gorilla-xmlrpc v0.0.0-20171012055324-ecf2fe693a2c h1:6xgMUqscagnZicBedm1h4T3q6IQHbrrZp7bker+toOI=\ngithub.com/ochinchina/gorilla-xmlrpc v0.0.0-20171012055324-ecf2fe693a2c/go.mod h1:/gFmJ8Das0jFgYxzt/RkvAO62T/ZPcyTaZlOkEBu/jw=\ngithub.com/ochinchina/supervisord/config v0.0.0-20220721095143-c2527852d28f/go.mod h1:jMN/SL0T6GCWWG/dD7Les9iPqjQ2OjEVyBWx8c9RJqI=\ngithub.com/ochinchina/supervisord/config v0.0.0-20230719054037-813956ff6a67 h1:u5/DJWJrK2k7uRPo2Oex1xam15ZKlIaRfmfYugeECS4=\ngithub.com/ochinchina/supervisord/config v0.0.0-20230719054037-813956ff6a67/go.mod h1:jMN/SL0T6GCWWG/dD7Les9iPqjQ2OjEVyBWx8c9RJqI=\ngithub.com/ochinchina/supervisord/events v0.0.0-20220721095143-c2527852d28f/go.mod h1:I+vx/d8jVSVe0nmhaJUPuouUnhpfUUiUbDciSDViL5I=\ngithub.com/ochinchina/supervisord/events v0.0.0-20230719054037-813956ff6a67 h1:hAS+XSoEc3szEJKdlbP1BFWIivUOyAnBfm5Ee9tL+cI=\ngithub.com/ochinchina/supervisord/events v0.0.0-20230719054037-813956ff6a67/go.mod h1:I+vx/d8jVSVe0nmhaJUPuouUnhpfUUiUbDciSDViL5I=\ngithub.com/ochinchina/supervisord/faults v0.0.0-20220721095143-c2527852d28f/go.mod h1:kReR3fnUfV2OHFESJ9IDriCTg/VU1D0cFfNPNOnMQCs=\ngithub.com/ochinchina/supervisord/faults v0.0.0-20230719054037-813956ff6a67 h1:dqmuzSF/uRe55HEcgHN5PtuKJGNVqZ54K7ucbiGQePw=\ngithub.com/ochinchina/supervisord/faults v0.0.0-20230719054037-813956ff6a67/go.mod h1:kReR3fnUfV2OHFESJ9IDriCTg/VU1D0cFfNPNOnMQCs=\ngithub.com/ochinchina/supervisord/logger v0.0.0-20220721095143-c2527852d28f/go.mod h1:DPIKvK0KqJdneJKrAqfLNgONWZ3m4cRAi96PG0A7deg=\ngithub.com/ochinchina/supervisord/logger v0.0.0-20230719054037-813956ff6a67 h1:Oi6D5XysnDTRo0Di3D+1MLfhNAjHmv/+eflPSOUFFOU=\ngithub.com/ochinchina/supervisord/logger v0.0.0-20230719054037-813956ff6a67/go.mod h1:DPIKvK0KqJdneJKrAqfLNgONWZ3m4cRAi96PG0A7deg=\ngithub.com/ochinchina/supervisord/process v0.0.0-20230719054037-813956ff6a67 h1:SHEZn3Qhc5SdhSAASQ9OCJuQGIT04HAmml1gIIEhVhU=\ngithub.com/ochinchina/supervisord/process v0.0.0-20230719054037-813956ff6a67/go.mod h1:QUKHvTSxsiZN56GSHhWN59LNropTaL5cwHtu97pvsVY=\ngithub.com/ochinchina/supervisord/signals v0.0.0-20220721095143-c2527852d28f/go.mod h1:o2x4RZxVWzKvgbSOv7G8z94pITwuweY+ZkITvp/VqGY=\ngithub.com/ochinchina/supervisord/signals v0.0.0-20230719054037-813956ff6a67 h1:ULpyG32Ravk2wnbqhMosCXvvmToSm3bTwRCstZ121Ms=\ngithub.com/ochinchina/supervisord/signals v0.0.0-20230719054037-813956ff6a67/go.mod h1:o2x4RZxVWzKvgbSOv7G8z94pITwuweY+ZkITvp/VqGY=\ngithub.com/ochinchina/supervisord/util v0.0.0-20220721095143-c2527852d28f/go.mod h1:V/yb0hfd2ax3Pzn83yoxBxww4HLJ5AXYH+rQBCieqcU=\ngithub.com/ochinchina/supervisord/util v0.0.0-20230719054037-813956ff6a67 h1:TGe+60SSuWJGK+N8PtsEEQ3VzfrdNjK5fColmRHau64=\ngithub.com/ochinchina/supervisord/util v0.0.0-20230719054037-813956ff6a67/go.mod h1:V/yb0hfd2ax3Pzn83yoxBxww4HLJ5AXYH+rQBCieqcU=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=\ngithub.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=\ngithub.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=\ngithub.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=\ngithub.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=\ngithub.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=\ngithub.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\ngithub.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=\ngithub.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=\ngithub.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=\ngithub.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\ngithub.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=\ngithub.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=\ngithub.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\ngithub.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=\ngithub.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=\ngithub.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=\ngithub.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=\ngithub.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=\ngithub.com/rogpeppe/go-charset v0.0.0-20190617161244-0dc95cdf6f31 h1:DE4LcMKyqAVa6a0CGmVxANbnVb7stzMmPkQiieyNmfQ=\ngithub.com/rogpeppe/go-charset v0.0.0-20190617161244-0dc95cdf6f31/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=\ngithub.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=\ngithub.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=\ngithub.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=\ngithub.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E=\ngithub.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=\ngithub.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8=\ngithub.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=\ngithub.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=\ngithub.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=\ngithub.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=\ngithub.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=\ngithub.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=\ngithub.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=\ngithub.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=\ngithub.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=\ngithub.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=\ngithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=\ngithub.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=\ngithub.com/theckman/go-flock v0.8.1 h1:kTixuOsFBOtGYSTLRLWK6GOs1hk/8OD11sR1pDd0dl4=\ngithub.com/theckman/go-flock v0.8.1/go.mod h1:kjuth3y9VJ2aNlkNEO99G/8lp9fMIKaGyBmh84IBheM=\ngithub.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=\ngithub.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=\ngithub.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=\ngithub.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngolang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=\ngolang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=\ngolang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=\ngolang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=\ngolang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=\ngolang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=\ngolang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=\ngolang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=\ngolang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=\ngolang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=\ngoogle.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=\ngopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=\ngorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=\ngorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=\ngorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "main.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage main\n\nimport (\n\t\"runtime\"\n\n\t\"github.com/IBAX-io/go-ibax/cmd\"\n)\n\nfunc main() {\n\truntime.LockOSThread()\n\tcmd.Execute()\n}\n"
  },
  {
    "path": "packages/api/api.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gorilla/schema\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tmultipartBuf      = 100000 // the buffer size for ParseMultipartForm\n\tmultipartFormData = \"multipart/form-data\"\n\tcontentType       = \"Content-Type\"\n)\n\ntype Mode struct {\n\tEcosystemGetter   types.EcosystemGetter\n\tContractRunner    types.SmartContractRunner\n\tClientTxProcessor types.ClientTxPreprocessor\n}\n\n// Client represents data of client\ntype Client struct {\n\tKeyID         int64\n\tAccountID     string\n\tEcosystemID   int64\n\tEcosystemName string\n\tRoleID        int64\n}\n\nfunc (c *Client) Prefix() string {\n\treturn converter.Int64ToStr(c.EcosystemID)\n}\n\nfunc jsonResponse(w http.ResponseWriter, v any) {\n\tjsonResult, err := json.Marshal(v)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marhsalling http response to json\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\tw.Write(jsonResult)\n}\n\nfunc errorResponse(w http.ResponseWriter, err error, code ...int) {\n\tet, ok := err.(errType)\n\tif !ok {\n\t\tet = errServer\n\t\tet.Message = err.Error()\n\t}\n\n\tw.Header().Set(\"X-Content-Type-Options\", \"nosniff\")\n\tif len(code) == 0 {\n\t\tw.WriteHeader(et.Status)\n\t} else {\n\t\tw.WriteHeader(code[0])\n\t}\n\n\tjsonResponse(w, et)\n}\n\ntype formValidator interface {\n\tValidate(r *http.Request) error\n}\n\ntype nopeValidator struct{}\n\nfunc (np nopeValidator) Validate(r *http.Request) error {\n\treturn nil\n}\n\nfunc parseForm(r *http.Request, f formValidator) (err error) {\n\tif isMultipartForm(r) {\n\t\terr = r.ParseMultipartForm(multipartBuf)\n\t} else {\n\t\terr = r.ParseForm()\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\n\tdecoder := schema.NewDecoder()\n\tdecoder.IgnoreUnknownKeys(true)\n\tif err := decoder.Decode(f, r.Form); err != nil {\n\t\treturn err\n\t}\n\treturn f.Validate(r)\n}\n\nfunc isMultipartForm(r *http.Request) bool {\n\treturn strings.HasPrefix(r.Header.Get(contentType), multipartFormData)\n}\n\ntype hexValue struct {\n\tvalue []byte\n}\n\nfunc (hv hexValue) Bytes() []byte {\n\treturn hv.value\n}\n\nfunc (hv *hexValue) UnmarshalText(v []byte) (err error) {\n\thv.value, err = hex.DecodeString(string(v))\n\treturn\n}\n"
  },
  {
    "path": "packages/api/api_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar apiAddress = \"http://localhost:7079\"\n\nvar (\n\tgAuth             string\n\tgAddress          string\n\tgPrivate, gPublic string\n)\n\n// PrivateToPublicHex returns the hex public key for the specified hex private key.\nfunc PrivateToPublicHex(hexkey string) (string, error) {\n\tkey, err := hex.DecodeString(hexkey)\n\tif err != nil {\n\t\treturn ``, fmt.Errorf(\"Decode hex error\")\n\t}\n\tpubKey, err := crypto.PrivateToPublic(key)\n\tif err != nil {\n\t\treturn ``, err\n\t}\n\treturn crypto.PubToHex(pubKey), nil\n}\n\nfunc sendRawRequest(rtype, url string, form *url.Values) ([]byte, error) {\n\tclient := &http.Client{}\n\tvar ioform io.Reader\n\tif form != nil {\n\t\tioform = strings.NewReader(form.Encode())\n\t}\n\treq, err := http.NewRequest(rtype, apiAddress+consts.ApiPath+url, ioform)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\tif len(gAuth) > 0 {\n\t\treq.Header.Set(\"Authorization\", jwtPrefix+gAuth)\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer resp.Body.Close()\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(`%d %s`, resp.StatusCode, strings.TrimSpace(string(data)))\n\t}\n\n\treturn data, nil\n}\n\nfunc sendRequest(rtype, url string, form *url.Values, v any) error {\n\tdata, err := sendRawRequest(rtype, url, form)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn json.Unmarshal(data, v)\n}\n\nfunc sendGet(url string, form *url.Values, v any) error {\n\treturn sendRequest(\"GET\", url, form, v)\n}\n\nfunc sendPost(url string, form *url.Values, v any) error {\n\treturn sendRequest(\"POST\", url, form, v)\n}\n\nfunc keyLogin(state int64) (err error) {\n\tvar (\n\t\tkey, sign []byte\n\t)\n\n\tkey, err = os.ReadFile(`key`)\n\tif err != nil {\n\t\treturn\n\t}\n\tif len(key) > 64 {\n\t\tkey = key[:64]\n\t}\n\tvar ret getUIDResult\n\terr = sendGet(`getuid`, nil, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\tgAuth = ret.Token\n\tif len(ret.UID) == 0 {\n\t\treturn fmt.Errorf(`getuid has returned empty uid`)\n\t}\n\n\tvar pub string\n\n\tsign, err = crypto.SignString(string(key), `LOGIN`+ret.NetworkID+ret.UID)\n\tif err != nil {\n\t\treturn\n\t}\n\tpub, err = PrivateToPublicHex(string(key))\n\tif err != nil {\n\t\treturn\n\t}\n\tform := url.Values{\"pubkey\": {pub}, \"signature\": {hex.EncodeToString(sign)},\n\t\t`ecosystem`: {converter.Int64ToStr(state)}, \"role_id\": {\"0\"}}\n\tvar logret loginResult\n\terr = sendPost(`login`, &form, &logret)\n\tif err != nil {\n\t\treturn\n\t}\n\tgAddress = logret.Account\n\tgPrivate = string(key)\n\tgPublic, err = PrivateToPublicHex(gPrivate)\n\tgAuth = logret.Token\n\tif err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc keyLoginToken(state int64) (err error) {\n\tvar (\n\t\tkey, sign []byte\n\t)\n\n\tstr, _ := os.Getwd()\n\tfmt.Println(\"dir \" + str)\n\tkey, err = os.ReadFile(`key`)\n\tif err != nil {\n\t\treturn\n\t}\n\tif len(key) > 64 {\n\t\tkey = key[:64]\n\t}\n\tvar ret getUIDResult\n\terr = sendGet(`getuid`, nil, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\tgAuth = ret.Token\n\tif len(ret.UID) == 0 {\n\t\treturn fmt.Errorf(`getuid has returned empty uid`)\n\t}\n\n\tvar pub string\n\n\tsign, err = crypto.SignString(string(key), `LOGIN`+ret.NetworkID+ret.UID)\n\tif err != nil {\n\t\treturn\n\t}\n\tpub, err = PrivateToPublicHex(string(key))\n\tif err != nil {\n\t\treturn\n\t}\n\tform := url.Values{\"pubkey\": {pub}, \"signature\": {hex.EncodeToString(sign)},\n\t\t`ecosystem`: {converter.Int64ToStr(state)}, \"role_id\": {\"0\"}, \"expire\": {\"5\"}}\n\tvar logret loginResult\n\terr = sendPost(`login`, &form, &logret)\n\tif err != nil {\n\t\treturn\n\t}\n\tgAddress = logret.Account\n\tgPrivate = string(key)\n\tgPublic, err = PrivateToPublicHex(gPrivate)\n\tgAuth = logret.Token\n\tif err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc keyLoginex(state int64, m ...string) (err error) {\n\tvar (\n\t\tkey, sign []byte\n\t)\n\n\tkey, err = os.ReadFile(`key` + m[0])\n\tif err != nil {\n\t\treturn\n\t}\n\tif len(key) > 64 {\n\t\tkey = key[:64]\n\t}\n\tvar ret getUIDResult\n\terr = sendGet(`getuid`, nil, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\tgAuth = ret.Token\n\tif len(ret.UID) == 0 {\n\t\treturn fmt.Errorf(`getuid has returned empty uid`)\n\t}\n\n\tvar pub string\n\n\tsign, err = crypto.SignString(string(key), `LOGIN`+ret.NetworkID+ret.UID)\n\tif err != nil {\n\t\treturn\n\t}\n\tpub, err = PrivateToPublicHex(string(key))\n\tif err != nil {\n\t\treturn\n\t}\n\tform := url.Values{\"pubkey\": {pub}, \"signature\": {hex.EncodeToString(sign)},\n\t\t`ecosystem`: {converter.Int64ToStr(state)}, \"role_id\": {\"0\"}}\n\tvar logret loginResult\n\terr = sendPost(`login`, &form, &logret)\n\tif err != nil {\n\t\treturn\n\t}\n\tgAddress = logret.Account\n\tgPrivate = string(key)\n\tgPublic, err = PrivateToPublicHex(gPrivate)\n\tgAuth = logret.Token\n\tif err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc waitTx(hash string) (blockid int64, penalty int64, err error) {\n\tdata, err := json.Marshal(&txstatusRequest{\n\t\tHashes: []string{hash},\n\t})\n\tif err != nil {\n\t\treturn\n\t}\n\n\tfor i := 0; i < 100; i++ {\n\t\tvar multiRet multiTxStatusResult\n\t\terr = sendPost(`txstatus`, &url.Values{\n\t\t\t\"data\": {string(data)},\n\t\t}, &multiRet)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tret := multiRet.Results[hash]\n\t\tvar errtext []byte\n\t\tif len(ret.BlockID) > 0 {\n\t\t\tblockid = converter.StrToInt64(ret.BlockID)\n\t\t\tpenalty = ret.Penalty\n\t\t\tif ret.Penalty == 1 {\n\t\t\t\terrtext, err = json.Marshal(ret.Message)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\terr = errors.New(string(errtext))\n\t\t\t\treturn\n\t\t\t} else {\n\t\t\t\terr = fmt.Errorf(ret.Result)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif ret.Message != nil {\n\t\t\terrtext, err = json.Marshal(ret.Message)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\terr = errors.New(string(errtext))\n\t\t\treturn\n\t\t}\n\t\ttime.Sleep(time.Second)\n\t}\n\n\treturn 0, 0, fmt.Errorf(`TxStatus timeout`)\n}\n\nfunc randName(prefix string) string {\n\treturn fmt.Sprintf(`%s%d`, prefix, time.Now().Unix())\n}\n\ntype getter interface {\n\tGet(string) string\n}\n\ntype contractParams map[string]any\n\nfunc (cp *contractParams) Get(key string) string {\n\tif _, ok := (*cp)[key]; !ok {\n\t\treturn \"\"\n\t}\n\treturn fmt.Sprintf(\"%v\", (*cp)[key])\n}\n\nfunc (cp *contractParams) GetRaw(key string) any {\n\treturn (*cp)[key]\n}\n\nfunc postTxResult(name string, form getter) (id int64, msg string, err error) {\n\tvar contract getContractResult\n\tif err = sendGet(\"contract/\"+name, nil, &contract); err != nil {\n\t\treturn\n\t}\n\n\tparams := make(map[string]any)\n\tfor _, field := range contract.Fields {\n\t\tname := field.Name\n\t\tvalue := form.Get(name)\n\n\t\tif len(value) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch field.Type {\n\t\tcase \"bool\":\n\t\t\tparams[name], err = strconv.ParseBool(value)\n\t\tcase \"int\", \"address\":\n\t\t\tparams[name], err = strconv.ParseInt(value, 10, 64)\n\t\tcase \"float\":\n\t\t\tparams[name], err = strconv.ParseFloat(value, 64)\n\t\tcase \"array\":\n\t\t\tvar v any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"map\":\n\t\t\tvar v map[string]any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"string\", \"money\":\n\t\t\tparams[name] = value\n\t\tcase \"file\", \"bytes\":\n\t\t\tif cp, ok := form.(*contractParams); !ok {\n\t\t\t\terr = fmt.Errorf(\"Form is not *contractParams type\")\n\t\t\t} else {\n\t\t\t\tparams[name] = cp.GetRaw(name)\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Parse param '%s': %s\", name, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar privateKey, publicKey []byte\n\tif privateKey, err = hex.DecodeString(gPrivate); err != nil {\n\t\treturn\n\t}\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\treturn\n\t}\n\n\tdata, hash, err := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(contract.ID),\n\t\t\tEcosystemID: 1,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tParams: params,\n\t\tLang:   \"en\",\n\t}, privateKey)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tret := &sendTxResult{}\n\terr = sendMultipart(\"sendTx\", map[string][]byte{\n\t\thex.EncodeToString(hash): data,\n\t}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\treturn\n\t}\n\tid, penalty, err := waitTx(ret.Hashes[hex.EncodeToString(hash)])\n\tif id != 0 && err != nil {\n\t\tif penalty == 1 {\n\t\t\treturn\n\t\t}\n\t\tmsg = err.Error()\n\t\terr = nil\n\t}\n\n\treturn\n}\n\nfunc postTxResultMultipart(name string, form getter) (id int64, msg string, err error) {\n\tvar contract getContractResult\n\tif err = sendGet(\"contract/\"+name, nil, &contract); err != nil {\n\t\treturn\n\t}\n\n\tparams := make(map[string]any)\n\tfor _, field := range contract.Fields {\n\t\tname := field.Name\n\t\tvalue := form.Get(name)\n\n\t\tif len(value) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch field.Type {\n\t\tcase \"bool\":\n\t\t\tparams[name], err = strconv.ParseBool(value)\n\t\tcase \"int\", \"address\":\n\t\t\tparams[name], err = strconv.ParseInt(value, 10, 64)\n\t\tcase \"float\":\n\t\t\tparams[name], err = strconv.ParseFloat(value, 64)\n\t\tcase \"array\":\n\t\t\tvar v any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"map\":\n\t\t\tvar v map[string]any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"string\", \"money\":\n\t\t\tparams[name] = value\n\t\tcase \"file\", \"bytes\":\n\t\t\tif cp, ok := form.(*contractParams); !ok {\n\t\t\t\terr = fmt.Errorf(\"Form is not *contractParams type\")\n\t\t\t} else {\n\t\t\t\tparams[name] = cp.GetRaw(name)\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Parse param '%s': %s\", name, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar privateKey, publicKey []byte\n\tif privateKey, err = hex.DecodeString(gPrivate); err != nil {\n\t\treturn\n\t}\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\treturn\n\t}\n\tarrData := make(map[string][]byte)\n\n\tfor i := 0; i < 1; i++ {\n\t\tconname := crypto.RandSeq(10)\n\t\tparams[\"ApplicationId\"] = int64(1)\n\t\tparams[\"Conditions\"] = \"1\"\n\t\t//params[\"TokenEcosystem\"] = int64(2)\n\t\tparams[\"Value\"] = fmt.Sprintf(`contract rnd%v%d  { action { }}`, conname, i)\n\t\texpedite := strconv.Itoa(1)\n\t\tdata, txhash, _ := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\t\tHeader: &types.Header{\n\t\t\t\tID:          int(contract.ID),\n\t\t\t\tTime:        time.Now().Unix(),\n\t\t\t\tEcosystemID: 1,\n\t\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t\t},\n\t\t\tParams:   params,\n\t\t\tExpedite: expedite,\n\t\t}, privateKey)\n\t\tarrData[fmt.Sprintf(\"%x\", txhash)] = data\n\t\tfmt.Println(fmt.Sprintf(\"%x\", txhash))\n\t}\n\tret := &sendTxResult{}\n\terr = sendMultipart(\"sendTx\", arrData, &ret)\n\t//err = sendMultipart(\"sendTx\", map[string][]byte{\n\t//\t\"data\": data,\n\t//}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\treturn\n\t}\n\n\t//var ids, ps []int64\n\t//\n\t//for s := range arrData {\n\t//\tid, penalty, err := waitTx(ret.Hashes[s])\n\t//\tids = append(ids, id)\n\t//\tps = append(ps, penalty)\n\t//\tif id != 0 && err != nil {\n\t//\t\tif penalty == 1 {\n\t//\t\t\t//return\n\t//\t\t}\n\t//\t\tmsg = err.Error()\n\t//\t\terr = nil\n\t//\t}\n\t//}\n\t//fmt.Println(ids, ps)\n\n\treturn\n}\n\nfunc postSignTxResult(name string, form getter) (id int64, msg string, err error) {\n\tvar contract getContractResult\n\tif err = sendGet(\"contract/\"+name, nil, &contract); err != nil {\n\t\treturn\n\t}\n\n\tparams := make(map[string]any)\n\tfor _, field := range contract.Fields {\n\t\tname := field.Name\n\t\tvalue := form.Get(name)\n\n\t\tif len(value) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch field.Type {\n\t\tcase \"bool\":\n\t\t\tparams[name], err = strconv.ParseBool(value)\n\t\tcase \"int\", \"address\":\n\t\t\tparams[name], err = strconv.ParseInt(value, 10, 64)\n\t\tcase \"float\":\n\t\t\tparams[name], err = strconv.ParseFloat(value, 64)\n\t\tcase \"array\":\n\t\t\tvar v any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"map\":\n\t\t\tvar v map[string]any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"string\", \"money\":\n\t\t\tparams[name] = value\n\t\tcase \"file\", \"bytes\":\n\t\t\tif cp, ok := form.(*contractParams); !ok {\n\t\t\t\terr = fmt.Errorf(\"Form is not *contractParams type\")\n\t\t\t} else {\n\t\t\t\tparams[name] = cp.GetRaw(name)\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Parse param '%s': %s\", name, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar privateKey, publicKey []byte\n\tif privateKey, err = hex.DecodeString(gPrivate); err != nil {\n\t\treturn\n\t}\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\treturn\n\t}\n\n\tdata, _, err := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(contract.ID),\n\t\t\tEcosystemID: 1,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tParams: params,\n\t}, privateKey)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tret := &sendTxResult{}\n\terr = sendMultipart(\"sendSignTx\", map[string][]byte{\n\t\t\"data\": data,\n\t}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\treturn\n\t}\n\tid, penalty, err := waitTx(ret.Hashes[\"data\"])\n\tif id != 0 && err != nil {\n\t\tif penalty == 1 {\n\t\t\treturn\n\t\t}\n\t\tmsg = err.Error()\n\t\terr = nil\n\t}\n\treturn\n}\n\nfunc postTxResult2(name string, form getter) (id int64, msg string, err error) {\n\tvar contract getContractResult\n\tif err = sendGet(\"contract/\"+name, nil, &contract); err != nil {\n\t\treturn\n\t}\n\n\tparams := make(map[string]any)\n\tfor _, field := range contract.Fields {\n\t\tname := field.Name\n\t\tvalue := form.Get(name)\n\n\t\tif len(value) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch field.Type {\n\t\tcase \"bool\":\n\t\t\tparams[name], err = strconv.ParseBool(value)\n\t\tcase \"int\", \"address\":\n\t\t\tparams[name], err = strconv.ParseInt(value, 10, 64)\n\t\tcase \"float\":\n\t\t\tparams[name], err = strconv.ParseFloat(value, 64)\n\t\tcase \"array\":\n\t\t\tvar v any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"map\":\n\t\t\tvar v map[string]any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"string\", \"money\":\n\t\t\tparams[name] = value\n\t\tcase \"file\", \"bytes\":\n\t\t\tif cp, ok := form.(*contractParams); !ok {\n\t\t\t\terr = fmt.Errorf(\"Form is not *contractParams type\")\n\t\t\t} else {\n\t\t\t\tparams[name] = cp.GetRaw(name)\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Parse param '%s': %s\", name, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar privateKey, publicKey []byte\n\tif privateKey, err = hex.DecodeString(gPrivate); err != nil {\n\t\treturn\n\t}\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\treturn\n\t}\n\n\tdata, _, err := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(contract.ID),\n\t\t\tEcosystemID: 2,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tParams: params,\n\t}, privateKey)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tret := &sendTxResult{}\n\terr = sendMultipart(\"sendTx\", map[string][]byte{\n\t\t\"data\": data,\n\t}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\treturn\n\t}\n\tid, penalty, err := waitTx(ret.Hashes[\"data\"])\n\tif id != 0 && err != nil {\n\t\tif penalty == 1 {\n\t\t\treturn\n\t\t}\n\t\tmsg = err.Error()\n\t\terr = nil\n\t}\n\treturn\n}\n\nfunc RawToString(input json.RawMessage) string {\n\tout := strings.Trim(string(input), `\"`)\n\treturn strings.Replace(out, `\\\"`, `\"`, -1)\n}\n\nfunc postTx(txname string, form *url.Values) error {\n\t_, _, err := postTxResult(txname, form)\n\treturn err\n}\n\nfunc postTxMultipart(txname string, form *url.Values) error {\n\t_, _, err := postTxResultMultipart(txname, form)\n\treturn err\n}\n\nfunc postTransferSelfTxMultipart(form *url.Values) error {\n\t_, _, err := postTransferSelfTxResult(form)\n\treturn err\n}\n\nfunc postUTXOTxMultipart(form *url.Values) error {\n\t_, _, err := postUTXOTxResult(form)\n\treturn err\n}\n\nfunc postTransferSelfTxResult(form getter) (id int64, msg string, err error) {\n\n\tvar privateKey, publicKey []byte\n\tif privateKey, err = hex.DecodeString(gPrivate); err != nil {\n\t\treturn\n\t}\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\treturn\n\t}\n\n\tdata, _, err := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(1),\n\t\t\tEcosystemID: 1,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tTransferSelf: &types.TransferSelf{\n\t\t\tValue: \"1000000000000000000\",\n\t\t\t//Asset:  \"IBAX\",\n\t\t\tSource: \"UTXO\",\n\t\t\tTarget: \"Account\",\n\t\t},\n\t}, privateKey)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tret := &sendTxResult{}\n\terr = sendMultipart(\"sendTx\", map[string][]byte{\n\t\t\"data\": data,\n\t}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\treturn\n\t}\n\tid, penalty, err := waitTx(ret.Hashes[\"data\"])\n\tif id != 0 && err != nil {\n\t\tif penalty == 1 {\n\t\t\treturn\n\t\t}\n\t\tmsg = err.Error()\n\t\terr = nil\n\t}\n\treturn\n}\n\nfunc postUTXOTxResult(form getter) (id int64, msg string, err error) {\n\n\tvar privateKey, publicKey []byte\n\tif privateKey, err = hex.DecodeString(gPrivate); err != nil {\n\t\treturn\n\t}\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\treturn\n\t}\n\n\tdata, _, err := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(1),\n\t\t\tEcosystemID: 1,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tUTXO: &types.UTXO{\n\t\t\tValue: \"1000000000000000\",\n\t\t\tToID:  -8055926748644556208,\n\t\t},\n\t}, privateKey)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tret := &sendTxResult{}\n\terr = sendMultipart(\"sendTx\", map[string][]byte{\n\t\t\"data\": data,\n\t}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\treturn\n\t}\n\tid, penalty, err := waitTx(ret.Hashes[\"data\"])\n\tif id != 0 && err != nil {\n\t\tif penalty == 1 {\n\t\t\treturn\n\t\t}\n\t\tmsg = err.Error()\n\t\terr = nil\n\t}\n\treturn\n}\n\nfunc postSignTx(txname string, form *url.Values) error {\n\t_, _, err := postSignTxResult(txname, form)\n\treturn err\n}\n\nfunc cutErr(err error) string {\n\tout := err.Error()\n\tif off := strings.IndexByte(out, '('); off != -1 {\n\t\tout = out[:off]\n\t}\n\treturn strings.TrimSpace(out)\n}\n\nfunc TestGetAvatar(t *testing.T) {\n\n\terr := keyLogin(1)\n\tassert.NoError(t, err)\n\n\turl := `http://localhost:7079` + consts.ApiPath + \"avatar/-1744264011260937456\"\n\treq, err := http.NewRequest(http.MethodGet, url, nil)\n\tassert.NoError(t, err)\n\n\tif len(gAuth) > 0 {\n\t\treq.Header.Set(\"Authorization\", jwtPrefix+gAuth)\n\t}\n\n\tcli := http.DefaultClient\n\tresp, err := cli.Do(req)\n\tassert.NoError(t, err)\n\n\tdefer resp.Body.Close()\n\tmime := resp.Header.Get(\"Content-Type\")\n\texpectedMime := \"image/png\"\n\tassert.Equal(t, expectedMime, mime, \"content type must be a '%s' but returns '%s'\", expectedMime, mime)\n}\n\nfunc sendMultipart(url string, files map[string][]byte, v any) error {\n\tbody := new(bytes.Buffer)\n\twriter := multipart.NewWriter(body)\n\n\tfor key, data := range files {\n\t\tpart, err := writer.CreateFormFile(key, key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := part.Write(data); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := writer.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treq, err := http.NewRequest(\"POST\", apiAddress+consts.ApiPath+url, body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n\tif len(gAuth) > 0 {\n\t\treq.Header.Set(\"Authorization\", jwtPrefix+gAuth)\n\t}\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(`%d %s`, resp.StatusCode, strings.TrimSpace(string(data)))\n\t}\n\n\treturn json.Unmarshal(data, &v)\n}\n"
  },
  {
    "path": "packages/api/app_content.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype appContentResult struct {\n\tSnippets  []sqldb.Snippet  `json:\"snippets\"`\n\tPages     []sqldb.Page     `json:\"pages\"`\n\tContracts []sqldb.Contract `json:\"contracts\"`\n}\n\nfunc (m Mode) getAppContentHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &appParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: m.EcosystemGetter,\n\t\t},\n\t}\n\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tlogger := getLogger(r)\n\tparams := mux.Vars(r)\n\n\tsni := &sqldb.Snippet{}\n\tp := &sqldb.Page{}\n\tc := &sqldb.Contract{}\n\tappID := converter.StrToInt64(params[\"appID\"])\n\tecosystemID := converter.StrToInt64(form.EcosystemPrefix)\n\n\tsnippets, err := sni.GetByApp(appID, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting block interfaces by appID\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tpages, err := p.GetByApp(appID, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting pages by appID\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tcontracts, err := c.GetByApp(appID, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting pages by appID\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, &appContentResult{\n\t\tSnippets:  snippets,\n\t\tPages:     pages,\n\t\tContracts: contracts,\n\t})\n}\n"
  },
  {
    "path": "packages/api/app_content_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestAppContent(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tvar ret appContentResult\n\terr := sendGet(`appcontent/1`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif len(ret.Snippets) == 0 {\n\t\tt.Error(\"incorrect snippets count\")\n\t}\n\n\tif len(ret.Contracts) == 0 {\n\t\tt.Error(\"incorrect contracts count\")\n\t}\n\n\tif len(ret.Pages) == 0 {\n\t\tt.Error(\"incorrent pages count\")\n\t}\n}\n"
  },
  {
    "path": "packages/api/appparam.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc (m Mode) GetAppParamHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\n\tform := &ecosystemForm{\n\t\tValidator: m.EcosystemGetter,\n\t}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\n\tap := &sqldb.AppParam{}\n\tap.SetTablePrefix(form.EcosystemPrefix)\n\tname := params[\"name\"]\n\tfound, err := ap.Get(nil, converter.StrToInt64(params[\"appID\"]), name)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting app parameter by name\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"key\": name}).Debug(\"app parameter not found\")\n\t\terrorResponse(w, errParamNotFound.Errorf(name))\n\t\treturn\n\t}\n\n\tjsonResponse(w, &paramResult{\n\t\tID:         converter.Int64ToStr(ap.ID),\n\t\tName:       ap.Name,\n\t\tValue:      ap.Value,\n\t\tConditions: ap.Conditions,\n\t})\n}\n"
  },
  {
    "path": "packages/api/appparams.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype appParamsResult struct {\n\tApp  string        `json:\"app_id\"`\n\tList []paramResult `json:\"list\"`\n}\n\ntype appParamsForm struct {\n\tecosystemForm\n\tparamsForm\n}\n\nfunc (f *appParamsForm) Validate(r *http.Request) error {\n\treturn f.ecosystemForm.Validate(r)\n}\n\nfunc (m Mode) getAppParamsHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &appParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: m.EcosystemGetter,\n\t\t},\n\t}\n\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\tap := &sqldb.AppParam{}\n\tap.SetTablePrefix(form.EcosystemPrefix)\n\n\tlist, err := ap.GetAllAppParameters(converter.StrToInt64(params[\"appID\"]), nil, nil, nil)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting all app parameters\")\n\t}\n\n\tresult := &appParamsResult{\n\t\tApp:  params[\"appID\"],\n\t\tList: make([]paramResult, 0),\n\t}\n\n\tacceptNames := form.AcceptNames()\n\tfor _, item := range list {\n\t\tif len(acceptNames) > 0 && !acceptNames[item.Name] {\n\t\t\tcontinue\n\t\t}\n\t\tresult.List = append(result.List, paramResult{\n\t\t\tID:         converter.Int64ToStr(item.ID),\n\t\t\tName:       item.Name,\n\t\t\tValue:      item.Value,\n\t\t\tConditions: item.Conditions,\n\t\t})\n\t}\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/auth.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/golang-jwt/jwt/v4\"\n)\n\nvar (\n\tjwtSecret       []byte\n\tjwtPrefix       = \"Bearer \"\n\tjwtExpire       = 28800 // By default, seconds\n\tjwtrefeshExpire = 600   // By default, seconds\n\t//jwtrefeshExpire = 10   // By default, seconds  test\n\n\terrJWTAuthValue      = errors.New(\"wrong authorization value\")\n\terrEcosystemNotFound = errors.New(\"ecosystem not found\")\n)\n\n// JWTClaims is storing jwt claims\ntype JWTClaims struct {\n\tUID         string `json:\"uid,omitempty\"`\n\tEcosystemID string `json:\"ecosystem_id,omitempty\"`\n\tKeyID       string `json:\"key_id,omitempty\"`\n\tAccountID   string `json:\"account_id,omitempty\"`\n\tRoleID      string `json:\"role_id,omitempty\"`\n\tjwt.RegisteredClaims\n}\n\nfunc generateJWTToken(claims JWTClaims) (string, error) {\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n\treturn token.SignedString(jwtSecret)\n}\n\nfunc parseJWTToken(header string) (*jwt.Token, error) {\n\tif len(header) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tif strings.HasPrefix(header, jwtPrefix) {\n\t\theader = header[len(jwtPrefix):]\n\t} else {\n\t\treturn nil, errJWTAuthValue\n\t}\n\n\treturn jwt.ParseWithClaims(header, &JWTClaims{}, func(token *jwt.Token) (any, error) {\n\t\tif _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {\n\t\t\treturn nil, fmt.Errorf(\"Unexpected signing method: %v\", token.Header[\"alg\"])\n\t\t}\n\t\treturn []byte(jwtSecret), nil\n\t})\n}\n\nfunc getClientFromToken(token *jwt.Token, ecosysNameService types.EcosystemGetter) (*Client, error) {\n\tclaims, ok := token.Claims.(*JWTClaims)\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\tif len(claims.KeyID) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tclient := &Client{\n\t\tEcosystemID: converter.StrToInt64(claims.EcosystemID),\n\t\tKeyID:       converter.StrToInt64(claims.KeyID),\n\t\tAccountID:   claims.AccountID,\n\t\tRoleID:      converter.StrToInt64(claims.RoleID),\n\t}\n\n\tsID := converter.StrToInt64(claims.EcosystemID)\n\tname, err := ecosysNameService.GetEcosystemName(sID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient.EcosystemName = name\n\treturn client, nil\n}\n\ntype authStatusResponse struct {\n\tIsActive  bool  `json:\"active\"`\n\tExpiresAt int64 `json:\"exp,omitempty\"`\n}\n\nfunc getAuthStatus(w http.ResponseWriter, r *http.Request) {\n\tresult := new(authStatusResponse)\n\tdefer jsonResponse(w, result)\n\n\ttoken := getToken(r)\n\tif token == nil {\n\t\treturn\n\t}\n\n\tclaims, ok := token.Claims.(*JWTClaims)\n\tif !ok {\n\t\treturn\n\t}\n\n\tresult.IsActive = true\n\tresult.ExpiresAt = claims.ExpiresAt.Unix()\n}\n\nfunc InitJwtSecret(secret []byte) {\n\tif secret == nil {\n\t\tpanic(\"jwt secret invalid\")\n\t}\n\tjwtSecret = secret\n}\n"
  },
  {
    "path": "packages/api/balance.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/gorilla/mux\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype balanceResult struct {\n\tAmount      string `json:\"amount\"`\n\tDigits      int64  `json:\"digits\"`\n\tTotal       string `json:\"total\"`\n\tUtxo        string `json:\"utxo\"`\n\tTokenSymbol string `json:\"token_symbol\"`\n\tTokenName   string `json:\"token_name\"`\n}\n\nfunc (m Mode) getBalanceHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\tform := &ecosystemForm{\n\t\tValidator: m.EcosystemGetter,\n\t}\n\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\n\tkeyID := converter.StringToAddress(params[\"wallet\"])\n\tif keyID == 0 {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConversionError, \"value\": params[\"wallet\"]}).Error(\"converting wallet to address\")\n\t\terrorResponse(w, errInvalidWallet.Errorf(params[\"wallet\"]))\n\t\treturn\n\t}\n\n\tkey := &sqldb.Key{}\n\tkey.SetTablePrefix(form.EcosystemID)\n\t_, err := key.Get(nil, keyID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting Key for wallet\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\taccountAmount, _ := decimal.NewFromString(key.Amount)\n\n\tsp := &sqldb.SpentInfo{}\n\tutxoAmount, err := sp.GetBalance(nil, keyID, form.EcosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting UTXO Key for wallet\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\ttotal := utxoAmount.Add(accountAmount)\n\n\teco := sqldb.Ecosystem{}\n\t_, err = eco.Get(nil, form.EcosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting key balance token symbol\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tjsonResponse(w, &balanceResult{\n\t\tAmount:      key.Amount,\n\t\tDigits:      eco.Digits,\n\t\tTotal:       total.String(),\n\t\tUtxo:        utxoAmount.String(),\n\t\tTokenSymbol: eco.TokenSymbol,\n\t\tTokenName:   eco.TokenName,\n\t})\n}\n"
  },
  {
    "path": "packages/api/balance_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc TestBalance(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret balanceResult\n\terr := sendGet(`balance/`+gAddress, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret.Amount) < 10 {\n\t\tt.Error(`too low balance`, ret)\n\t}\n\terr = sendGet(`balance/3434341`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret.Amount) > 0 {\n\t\tt.Error(fmt.Errorf(`wrong balance %s`, ret.Amount))\n\t\treturn\n\t}\n}\n\nfunc TestMoneyMoreSend(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\t//for i := 0; i < 100; i++ {\n\t//\tform := url.Values{`Amount`: {`1`}, `Recipient`: {`1088-3972-0775-1704-9008`}, `Comment`: {`Test`}}\n\t//\tif err := postSignTx(`TokensSend`, &form); err != nil {\n\t//\t\tt.Error(err)\n\t//\t\treturn\n\t//\t}\n\t//\ttime.Sleep(2 * time.Second)\n\t//}\n\t//for i := 0; i < 2; i++ {\n\t//\tform := url.Values{`Amount`: {`-1`}, `Recipient`: {`1088-3972-0775-1704-9008`}, `Comment`: {`Test`}}\n\t//\tif err := postTx(`TokensSend`, &form); err != nil {\n\t//\t\tt.Error(err)\n\t//\t\treturn\n\t//\t}\n\t//\ttime.Sleep(2 * time.Second)\n\t//}\n\n\tform := url.Values{`Amount`: {`-1`}, `Account`: {`0323-3625-0280-2110-5478`}, `Type`: {`1`}}\n\tif err := postTx(`AddAssignMember`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n}\n"
  },
  {
    "path": "packages/api/block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/common\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype maxBlockResult struct {\n\tMaxBlockID int64 `json:\"max_block_id\"`\n}\n\nfunc getMaxBlockHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\n\tblock := &sqldb.BlockChain{}\n\tfound, err := block.GetMaxBlock()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting max block\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"last block not found\")\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tjsonResponse(w, &maxBlockResult{block.ID})\n}\n\ntype blockInfoResult struct {\n\tHash          []byte `json:\"hash\"`\n\tEcosystemID   int64  `json:\"ecosystem_id\"`\n\tKeyID         int64  `json:\"key_id\"`\n\tTime          int64  `json:\"time\"`\n\tTx            int32  `json:\"tx_count\"`\n\tRollbacksHash []byte `json:\"rollbacks_hash\"`\n\tNodePosition  int64  `json:\"node_position\"`\n\tConsensusMode int32  `json:\"consensus_mode\"`\n}\n\nfunc getBlockInfoHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\tparams := mux.Vars(r)\n\n\tblockID := converter.StrToInt64(params[\"id\"])\n\tblock := sqldb.BlockChain{}\n\tfound, err := block.Get(blockID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting block\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"id\": blockID}).Debug(\"block with id not found\")\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tjsonResponse(w, &blockInfoResult{\n\t\tHash:          block.Hash,\n\t\tEcosystemID:   block.EcosystemID,\n\t\tKeyID:         block.KeyID,\n\t\tTime:          block.Time,\n\t\tTx:            block.Tx,\n\t\tRollbacksHash: block.RollbacksHash,\n\t\tNodePosition:  block.NodePosition,\n\t\tConsensusMode: block.ConsensusMode,\n\t})\n}\n\ntype TxInfo struct {\n\tHash         []byte         `json:\"hash\"`\n\tContractName string         `json:\"contract_name\"`\n\tParams       map[string]any `json:\"params\"`\n\tKeyID        int64          `json:\"key_id\"`\n}\n\ntype blocksTxInfoForm struct {\n\tBlockID int64 `schema:\"block_id\"`\n\tCount   int64 `schema:\"count\"`\n}\n\nfunc (f *blocksTxInfoForm) Validate(r *http.Request) error {\n\tif f.BlockID > 0 {\n\t\tf.BlockID--\n\t}\n\tif f.Count <= 0 {\n\t\tf.Count = defaultPaginatorLimit\n\t}\n\n\tif f.Count > maxPaginatorLimit {\n\t\tf.Count = maxPaginatorLimit\n\t}\n\treturn nil\n}\n\nfunc getBlocksTxInfoHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &blocksTxInfoForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif form.BlockID < 0 || form.Count < 0 {\n\t\terr := errors.New(\"parameter is invalid\")\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\tlogger := getLogger(r)\n\n\tblocks, err := sqldb.GetBlockchain(form.BlockID, form.BlockID+form.Count, sqldb.OrderASC)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting blocks range\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif len(blocks) == 0 {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tresult := map[int64][]TxInfo{}\n\tfor _, blockModel := range blocks {\n\t\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(blockModel.Data), false)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err, \"bolck_id\": blockModel.ID}).Error(\"on unmarshalling block\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\n\t\ttxInfoCollection := make([]TxInfo, 0, len(blck.Transactions))\n\t\tfor _, tx := range blck.Transactions {\n\t\t\ttxInfo := TxInfo{\n\t\t\t\tHash: tx.Hash(),\n\t\t\t}\n\n\t\t\tif tx.IsSmartContract() {\n\t\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\t\ttxInfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t\t}\n\t\t\t\ttxInfo.Params = tx.SmartContract().TxData\n\t\t\t}\n\n\t\t\tif blck.IsGenesis() {\n\t\t\t\ttxInfo.KeyID = blck.Header.KeyId\n\t\t\t} else {\n\t\t\t\ttxInfo.KeyID = tx.KeyID()\n\t\t\t}\n\n\t\t\ttxInfoCollection = append(txInfoCollection, txInfo)\n\n\t\t\tlogger.WithFields(log.Fields{\"block_id\": blockModel.ID, \"tx hash\": txInfo.Hash, \"contract_name\": txInfo.ContractName, \"key_id\": txInfo.KeyID, \"params\": txInfoCollection}).Debug(\"BlockChain Transactions Information\")\n\t\t}\n\n\t\tresult[blockModel.ID] = txInfoCollection\n\t}\n\n\tjsonResponse(w, &result)\n}\n\ntype TxDetailedInfo struct {\n\tHash         []byte         `json:\"hash\"`\n\tContractName string         `json:\"contract_name\"`\n\tParams       map[string]any `json:\"params\"`\n\tKeyID        int64          `json:\"key_id\"`\n\tTime         int64          `json:\"time\"`\n\tType         byte           `json:\"type\"`\n\tSize         string         `json:\"size\"`\n}\n\ntype BlockHeaderInfo struct {\n\tBlockID      int64  `json:\"block_id\"`\n\tTime         int64  `json:\"time\"`\n\tEcosystemID  int64  `json:\"-\"`\n\tKeyID        int64  `json:\"key_id\"`\n\tNodePosition int64  `json:\"node_position\"`\n\tSign         []byte `json:\"-\"`\n\tHash         []byte `json:\"-\"`\n\tVersion      int    `json:\"version\"`\n}\n\ntype BlockDetailedInfo struct {\n\tHeader        BlockHeaderInfo  `json:\"header\"`\n\tHash          []byte           `json:\"hash\"`\n\tEcosystemID   int64            `json:\"-\"`\n\tNodePosition  int64            `json:\"node_position\"`\n\tKeyID         int64            `json:\"key_id\"`\n\tTime          int64            `json:\"time\"`\n\tTx            int32            `json:\"tx_count\"`\n\tSize          string           `json:\"size\"`\n\tRollbacksHash []byte           `json:\"rollbacks_hash\"`\n\tMerkleRoot    []byte           `json:\"merkle_root\"`\n\tBinData       []byte           `json:\"bin_data\"`\n\tSysUpdate     bool             `json:\"-\"`\n\tGenBlock      bool             `json:\"-\"`\n\tStopCount     int              `json:\"stop_count\"`\n\tTransactions  []TxDetailedInfo `json:\"transactions\"`\n}\n\nfunc getBlocksDetailedInfoHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &blocksTxInfoForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\tif form.BlockID < 0 || form.Count < 0 {\n\t\terr := errors.New(\"parameter is invalid\")\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tlogger := getLogger(r)\n\n\tblocks, err := sqldb.GetBlockchain(form.BlockID, form.BlockID+form.Count, sqldb.OrderASC)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting blocks range\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif len(blocks) == 0 {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tresult := map[int64]BlockDetailedInfo{}\n\tfor _, blockModel := range blocks {\n\t\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(blockModel.Data), false)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err, \"block_id\": blockModel.ID}).Error(\"on unmarshalling block\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\n\t\ttxDetailedInfoCollection := make([]TxDetailedInfo, 0, len(blck.Transactions))\n\t\tfor _, tx := range blck.Transactions {\n\t\t\ttxDetailedInfo := TxDetailedInfo{\n\t\t\t\tHash:  tx.Hash(),\n\t\t\t\tKeyID: tx.KeyID(),\n\t\t\t\tTime:  tx.Timestamp(),\n\t\t\t\tType:  tx.Type(),\n\t\t\t\tSize:  common.StorageSize(len(tx.Payload())).TerminalString(),\n\t\t\t}\n\n\t\t\tif tx.IsSmartContract() {\n\t\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\t\ttxDetailedInfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t\t}\n\t\t\t\ttxDetailedInfo.Params = tx.SmartContract().TxData\n\t\t\t\tif tx.Type() == types.TransferSelfTxType {\n\t\t\t\t\ttxDetailedInfo.Params = make(map[string]any)\n\t\t\t\t\ttxDetailedInfo.Params[\"TransferSelf\"] = tx.SmartContract().TxSmart.TransferSelf\n\t\t\t\t}\n\t\t\t\tif tx.Type() == types.UtxoTxType {\n\t\t\t\t\ttxDetailedInfo.Params = make(map[string]any)\n\t\t\t\t\ttxDetailedInfo.Params[\"UTXO\"] = tx.SmartContract().TxSmart.UTXO\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttxDetailedInfoCollection = append(txDetailedInfoCollection, txDetailedInfo)\n\n\t\t\tlogger.WithFields(log.Fields{\"block_id\": blockModel.ID, \"tx hash\": txDetailedInfo.Hash, \"contract_name\": txDetailedInfo.ContractName, \"key_id\": txDetailedInfo.KeyID, \"time\": txDetailedInfo.Time, \"type\": txDetailedInfo.Type, \"params\": txDetailedInfoCollection}).Debug(\"BlockChain Transactions Information\")\n\t\t}\n\n\t\theader := BlockHeaderInfo{\n\t\t\tBlockID:      blck.Header.BlockId,\n\t\t\tTime:         blck.Header.Timestamp,\n\t\t\tEcosystemID:  blck.Header.EcosystemId,\n\t\t\tKeyID:        blck.Header.KeyId,\n\t\t\tNodePosition: blck.Header.NodePosition,\n\t\t\tSign:         blck.Header.Sign,\n\t\t\tHash:         blck.Header.BlockHash,\n\t\t\tVersion:      int(blck.Header.Version),\n\t\t}\n\n\t\tbdi := BlockDetailedInfo{\n\t\t\tHeader:        header,\n\t\t\tHash:          blockModel.Hash,\n\t\t\tEcosystemID:   blockModel.EcosystemID,\n\t\t\tNodePosition:  blockModel.NodePosition,\n\t\t\tKeyID:         blockModel.KeyID,\n\t\t\tTime:          blockModel.Time,\n\t\t\tTx:            blockModel.Tx,\n\t\t\tRollbacksHash: blockModel.RollbacksHash,\n\t\t\tMerkleRoot:    blck.MerkleRoot,\n\t\t\tBinData:       blck.BinData,\n\t\t\tSize:          common.StorageSize(len(blockModel.Data)).TerminalString(),\n\t\t\tSysUpdate:     blck.SysUpdate,\n\t\t\tGenBlock:      blck.GenBlock,\n\t\t\tTransactions:  txDetailedInfoCollection,\n\t\t}\n\t\tresult[blockModel.ID] = bdi\n\t}\n\n\tjsonResponse(w, &result)\n}\n"
  },
  {
    "path": "packages/api/block_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetMaxBlockID(t *testing.T) {\n\tvar ret maxBlockResult\n\terr := sendGet(`maxblockid`, nil, &ret)\n\tassert.NoError(t, err)\n}\n\nfunc TestGetBlockInfo(t *testing.T) {\n\tvar ret blockInfoResult\n\terr := sendGet(`block/1`, nil, &ret)\n\tassert.NoError(t, err)\n}\n"
  },
  {
    "path": "packages/api/common_forms.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nconst (\n\tdefaultPaginatorLimit = 25\n\tmaxPaginatorLimit     = 1000\n)\n\ntype paginatorForm struct {\n\tdefaultLimit int\n\n\tLimit  int `schema:\"limit\"`\n\tOffset int `schema:\"offset\"`\n}\n\nfunc (f *paginatorForm) Validate(r *http.Request) error {\n\tif f.Limit <= 0 {\n\t\tf.Limit = f.defaultLimit\n\t\tif f.Limit == 0 {\n\t\t\tf.Limit = defaultPaginatorLimit\n\t\t}\n\t}\n\n\tif f.Limit > maxPaginatorLimit {\n\t\tf.Limit = maxPaginatorLimit\n\t}\n\n\treturn nil\n}\n\ntype paramsForm struct {\n\tnopeValidator\n\tNames string `schema:\"names\"`\n}\n\nfunc (f *paramsForm) AcceptNames() map[string]bool {\n\tnames := make(map[string]bool)\n\tfor _, item := range strings.Split(f.Names, \",\") {\n\t\tif len(item) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tnames[item] = true\n\t}\n\treturn names\n}\n\ntype ecosystemForm struct {\n\tEcosystemID     int64  `schema:\"ecosystem\"`\n\tEcosystemPrefix string `schema:\"-\"`\n\tValidator       types.EcosystemGetter\n}\n\nfunc (f *ecosystemForm) Validate(r *http.Request) error {\n\tif f.Validator == nil {\n\t\tpanic(\"ecosystemForm.Validator should not be empty\")\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tecosysID, err := f.Validator.ValidateId(f.EcosystemID, client.EcosystemID, logger)\n\tif err != nil {\n\t\tif err == ErrEcosystemNotFound {\n\t\t\terr = errEcosystem.Errorf(f.EcosystemID)\n\t\t}\n\t\treturn err\n\t}\n\n\tf.EcosystemID = ecosysID\n\tf.EcosystemPrefix = converter.Int64ToStr(f.EcosystemID)\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/api/config.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/publisher\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype configOptionHandler func(w http.ResponseWriter, option string) error\n\nfunc getConfigOptionHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\tif len(params[\"option\"]) == 0 {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject, \"error\": \"option not specified\"}).Error(\"on getting option in config handler\")\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tswitch params[\"option\"] {\n\tcase \"centrifugo\":\n\t\tcentrifugoAddressHandler(w, r)\n\t\treturn\n\t}\n\n\terrorResponse(w, errNotFound)\n}\n\nfunc replaceHttpSchemeToWs(centrifugoURL string) string {\n\tif strings.HasPrefix(centrifugoURL, \"http:\") {\n\t\treturn strings.Replace(centrifugoURL, \"http:\", \"ws:\", -1)\n\t} else if strings.HasPrefix(centrifugoURL, \"https:\") {\n\t\treturn strings.Replace(centrifugoURL, \"https:\", \"wss:\", -1)\n\t}\n\treturn centrifugoURL\n}\n\nfunc centrifugoAddressHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\n\tif _, err := publisher.GetStats(); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.CentrifugoError, \"error\": err}).Warn(\"on getting centrifugo stats\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, replaceHttpSchemeToWs(conf.Config.Centrifugo.URL))\n}\n"
  },
  {
    "path": "packages/api/content.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/template\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype contentResult struct {\n\tMenu       string          `json:\"menu,omitempty\"`\n\tMenuTree   json.RawMessage `json:\"menutree,omitempty\"`\n\tTitle      string          `json:\"title,omitempty\"`\n\tTree       json.RawMessage `json:\"tree\"`\n\tNodesCount int64           `json:\"nodesCount,omitempty\"`\n}\n\ntype hashResult struct {\n\tHash string `json:\"hash\"`\n}\n\nconst (\n\tstrTrue = `true`\n\tstrOne  = `1`\n)\n\nvar errEmptyTemplate = errors.New(\"Empty template\")\n\nfunc initVars(r *http.Request) *map[string]string {\n\tclient := getClient(r)\n\tr.ParseMultipartForm(multipartBuf)\n\n\tvars := make(map[string]string)\n\tfor name := range r.Form {\n\t\tvars[name] = r.FormValue(name)\n\t}\n\tvars[\"_full\"] = \"0\"\n\tvars[\"current_time\"] = fmt.Sprintf(\"%d\", time.Now().Unix())\n\tvars[\"guest_key\"] = consts.GuestKey\n\tvars[\"guest_account\"] = consts.GuestAddress\n\tvars[\"black_hole_key\"] = strconv.FormatInt(converter.HoleAddrMap[converter.BlackHoleAddr].K, 10)\n\tvars[\"black_hole_account\"] = converter.HoleAddrMap[converter.BlackHoleAddr].S\n\tvars[\"white_hole_key\"] = strconv.FormatInt(converter.HoleAddrMap[converter.WhiteHoleAddr].K, 10)\n\tvars[\"white_hole_account\"] = converter.HoleAddrMap[converter.WhiteHoleAddr].S\n\tif client.KeyID != 0 {\n\t\tvars[\"ecosystem_id\"] = converter.Int64ToStr(client.EcosystemID)\n\t\tvars[\"key_id\"] = converter.Int64ToStr(client.KeyID)\n\t\tvars[\"account_id\"] = client.AccountID\n\t\tvars[\"role_id\"] = converter.Int64ToStr(client.RoleID)\n\t\tvars[\"ecosystem_name\"] = client.EcosystemName\n\t} else {\n\t\tvars[\"ecosystem_id\"] = vars[\"ecosystem\"]\n\t\tdelete(vars, \"ecosystem\")\n\t\tif len(vars[\"keyID\"]) > 0 {\n\t\t\tvars[\"key_id\"] = vars[\"keyID\"]\n\t\t\tvars[\"account_id\"] = converter.AddressToString(converter.StrToInt64(vars[\"keyID\"]))\n\t\t} else {\n\t\t\tvars[\"key_id\"] = \"0\"\n\t\t\tvars[\"account_id\"] = \"\"\n\t\t}\n\t\tif len(vars[\"roleID\"]) > 0 {\n\t\t\tvars[\"role_id\"] = vars[\"roleID\"]\n\t\t} else {\n\t\t\tvars[\"role_id\"] = \"0\"\n\t\t}\n\t\tif len(vars[\"ecosystem_id\"]) != 0 {\n\t\t\tecosystems := sqldb.Ecosystem{}\n\t\t\tif found, _ := ecosystems.Get(nil, converter.StrToInt64(vars[\"ecosystem_id\"])); found {\n\t\t\t\tvars[\"ecosystem_name\"] = ecosystems.Name\n\t\t\t}\n\t\t}\n\t}\n\tif _, ok := vars[\"lang\"]; !ok {\n\t\tvars[\"lang\"] = r.Header.Get(\"Accept-Language\")\n\t}\n\n\treturn &vars\n}\n\nfunc parseEcosystem(in string) (string, string) {\n\tecosystem, name := converter.ParseName(in)\n\tif ecosystem == 0 {\n\t\treturn ``, name\n\t}\n\treturn converter.Int64ToStr(ecosystem), name\n}\n\nfunc pageValue(r *http.Request) (*sqldb.Page, string, error) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\n\tvar ecosystem string\n\tpage := &sqldb.Page{}\n\tname := params[\"name\"]\n\tif strings.HasPrefix(name, `@`) {\n\t\tecosystem, name = parseEcosystem(name)\n\t\tif len(name) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\n\t\t\t\t\"type\":  consts.NotFound,\n\t\t\t\t\"value\": params[\"name\"],\n\t\t\t}).Debug(\"page not found\")\n\t\t\treturn nil, ``, errNotFound\n\t\t}\n\t} else {\n\t\tecosystem = client.Prefix()\n\t}\n\tpage.SetTablePrefix(ecosystem)\n\tfound, err := page.Get(name)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting page\")\n\t\treturn nil, ``, err\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"page not found\")\n\t\treturn nil, ``, errNotFound\n\t}\n\treturn page, ecosystem, nil\n}\n\nfunc getPage(r *http.Request) (result *contentResult, err error) {\n\tpage, _, err := pageValue(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogger := getLogger(r)\n\n\tclient := getClient(r)\n\tmenu := &sqldb.Menu{}\n\tmenu.SetTablePrefix(client.Prefix())\n\t_, err = menu.Get(page.Menu)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting page menu\")\n\t\treturn nil, errServer\n\t}\n\tvar wg sync.WaitGroup\n\tvar timeout bool\n\twg.Add(2)\n\tsuccess := make(chan bool, 1)\n\tgo func() {\n\t\tdefer wg.Done()\n\n\t\tvars := initVars(r)\n\t\t(*vars)[\"app_id\"] = converter.Int64ToStr(page.AppID)\n\n\t\tret := template.Template2JSON(page.Value, &timeout, vars)\n\t\tif timeout {\n\t\t\treturn\n\t\t}\n\t\tretmenu := template.Template2JSON(menu.Value, &timeout, vars)\n\t\tif timeout {\n\t\t\treturn\n\t\t}\n\t\tresult = &contentResult{\n\t\t\tTree:       ret,\n\t\t\tMenu:       page.Menu,\n\t\t\tMenuTree:   retmenu,\n\t\t\tNodesCount: page.ValidateCount,\n\t\t}\n\t\tsuccess <- true\n\t}()\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tif conf.Config.LocalConf.MaxPageGenerationTime == 0 {\n\t\t\treturn\n\t\t}\n\t\tselect {\n\t\tcase <-time.After(time.Duration(conf.Config.LocalConf.MaxPageGenerationTime) * time.Millisecond):\n\t\t\ttimeout = true\n\t\tcase <-success:\n\t\t}\n\t}()\n\twg.Wait()\n\tclose(success)\n\n\tif timeout {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.InvalidObject}).Error(page.Name + \" is a heavy page\")\n\t\treturn nil, errHeavyPage\n\t}\n\n\treturn result, nil\n}\n\nfunc getPageHandler(w http.ResponseWriter, r *http.Request) {\n\tresult, err := getPage(r)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, result)\n}\n\nfunc getPageHashHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\tparams := mux.Vars(r)\n\n\tif ecosystem := r.FormValue(\"ecosystem\"); len(ecosystem) > 0 &&\n\t\t!strings.HasPrefix(params[\"name\"], \"@\") {\n\t\tparams[\"name\"] = \"@\" + ecosystem + params[\"name\"]\n\t}\n\tresult, err := getPage(r)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tout, err := json.Marshal(result)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"getting string for hash\")\n\t\terrorResponse(w, errServer)\n\t\treturn\n\t}\n\n\tjsonResponse(w, &hashResult{Hash: hex.EncodeToString(crypto.Hash(out))})\n}\n\nfunc getMenuHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tvar ecosystem string\n\tmenu := &sqldb.Menu{}\n\tname := params[\"name\"]\n\tif strings.HasPrefix(name, `@`) {\n\t\tecosystem, name = parseEcosystem(name)\n\t\tif len(name) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\n\t\t\t\t\"type\":  consts.NotFound,\n\t\t\t\t\"value\": params[\"name\"],\n\t\t\t}).Debug(\"page not found\")\n\t\t\terrorResponse(w, errNotFound)\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tecosystem = client.Prefix()\n\t}\n\n\tmenu.SetTablePrefix(ecosystem)\n\tfound, err := menu.Get(name)\n\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting menu\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"menu not found\")\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\tvar timeout bool\n\tret := template.Template2JSON(menu.Value, &timeout, initVars(r))\n\tjsonResponse(w, &contentResult{Tree: ret, Title: menu.Title})\n}\n\ntype jsonContentForm struct {\n\tTemplate string `schema:\"template\"`\n\tSource   bool   `schema:\"source\"`\n}\n\nfunc (f *jsonContentForm) Validate(r *http.Request) error {\n\tif len(f.Template) == 0 {\n\t\treturn errEmptyTemplate\n\t}\n\treturn nil\n}\n\nfunc jsonContentHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &jsonContentForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tvar timeout bool\n\tvars := initVars(r)\n\n\tif form.Source {\n\t\t(*vars)[\"_full\"] = strOne\n\t}\n\n\tret := template.Template2JSON(form.Template, &timeout, vars)\n\tjsonResponse(w, &contentResult{Tree: ret})\n}\n\nfunc getSourceHandler(w http.ResponseWriter, r *http.Request) {\n\tpage, _, err := pageValue(r)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tvar timeout bool\n\tvars := initVars(r)\n\t(*vars)[\"_full\"] = strOne\n\tret := template.Template2JSON(page.Value, &timeout, vars)\n\n\tjsonResponse(w, &contentResult{Tree: ret})\n}\n\nfunc getPageValidatorsCountHandler(w http.ResponseWriter, r *http.Request) {\n\tpage, _, err := pageValue(r)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tres := map[string]int64{\"validate_count\": page.ValidateCount}\n\tjsonResponse(w, &res)\n}\n"
  },
  {
    "path": "packages/api/content_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestContentHash(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`page`)\n\tassert.NoError(t, postTx(`NewPage`, &url.Values{\n\t\t\"ApplicationId\": {`1`},\n\t\t\"Name\":          {name},\n\t\t\"Value\":         {`Div(Body: \"New value of parameter - test\")`},\n\t\t\"Menu\":          {`default_menu`},\n\t\t\"Conditions\":    {\"true\"},\n\t}))\n\turls := \"content/page/\" + name\n\tvar ret contentResult\n\tassert.NoError(t, sendPost(urls, &url.Values{}, &ret))\n\tout, err := json.Marshal(ret)\n\tassert.NoError(t, err)\n\thash := crypto.Hash(out)\n\turls = \"content/hash/\" + name\n\tvar hret hashResult\n\tassert.NoError(t, sendPost(urls, &url.Values{}, &hret))\n\tif hex.EncodeToString(hash) != hret.Hash {\n\t\tt.Error(`wrong hash`, hex.EncodeToString(hash), hret.Hash)\n\t}\n}\n\nfunc TestContent(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`page`)\n\tassert.NoError(t, postTx(`NewPage`, &url.Values{\n\t\t\"ApplicationId\": {`1`},\n\t\t\"Name\":          {name},\n\t\t\"Value\":         {`If(true){Div(){Span(My text)Address()}}.Else{Div(Body: Hidden text)}`},\n\t\t\"Menu\":          {`default_menu`},\n\t\t\"Conditions\":    {\"true\"},\n\t}))\n\n\tcases := []struct {\n\t\turl      string\n\t\tform     url.Values\n\t\texpected string\n\t}{\n\t\t{\n\t\t\t\"content/source/\" + name,\n\t\t\turl.Values{},\n\t\t\t`[{\"tag\":\"if\",\"attr\":{\"condition\":\"true\"},\"children\":[{\"tag\":\"div\",\"children\":[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"My text\"}]},{\"tag\":\"address\"}]}],\"tail\":[{\"tag\":\"else\",\"children\":[{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"Hidden text\"}]}]}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {\"input Div(myclass, #mytest# Div(mypar) the Div)\"},\n\t\t\t\t\"mytest\":   {\"test value\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"text\",\"text\":\"input \"},{\"tag\":\"div\",\"attr\":{\"class\":\"myclass\"},\"children\":[{\"tag\":\"text\",\"text\":\"test value \"},{\"tag\":\"div\",\"attr\":{\"class\":\"mypar\"}},{\"tag\":\"text\",\"text\":\" the Div\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\":  {\"#test_page# input Div(myclass, #test_page# ok) #test_page#\"},\n\t\t\t\t\"test_page\": {\"7\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"text\",\"text\":\"7 input \"},{\"tag\":\"div\",\"attr\":{\"class\":\"myclass\"},\"children\":[{\"tag\":\"text\",\"text\":\"7 ok\"}]},{\"tag\":\"text\",\"text\":\" 7\"}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {\"SetVar(mytest, myvar)Div(myclass, Span(#mytest#) Div(mypar){Span(test)}#mytest#)\"},\n\t\t\t\t\"source\":   {\"true\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"setvar\",\"attr\":{\"name\":\"mytest\",\"value\":\"myvar\"}},{\"tag\":\"div\",\"attr\":{\"class\":\"myclass\"},\"children\":[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"#mytest#\"}]},{\"tag\":\"div\",\"attr\":{\"class\":\"mypar\"},\"children\":[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"test\"}]}]},{\"tag\":\"text\",\"text\":\"#mytest#\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {`DBFind(Name: pages, Source: src).Custom(custom_col){\n\t\t\t\tSpan(Body: \"test\")\n\t\t\t}`},\n\t\t\t\t\"lang\":   {\"ru\"},\n\t\t\t\t\"source\": {\"true\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"name\":\"pages\",\"source\":\"src\"},\"tail\":[{\"tag\":\"custom\",\"attr\":{\"column\":\"custom_col\"},\"children\":[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"test\"}]}]}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {`Data(Source: src).Custom(custom_col){\n\t\t\t\tSpan(Body: \"test\")\n\t\t\t}`},\n\t\t\t\t\"lang\":   {\"ru\"},\n\t\t\t\t\"source\": {\"true\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"data\",\"attr\":{\"source\":\"src\"},\"tail\":[{\"tag\":\"custom\",\"attr\":{\"column\":\"custom_col\"},\"children\":[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"test\"}]}]}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {`Data(myforlist,\"id,name\",\n\t\t\t\t\t\"1\",Test message 1\n\t\t\t\t\t2,\"Test message 2\"\n\t\t\t\t\t3,\"Test message 3\"\n\t\t\t\t\t)`},\n\t\t\t\t\"source\": {\"true\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"data\",\"attr\":{\"columns\":\"id,name\",\"data\":\"1,Test message 1\\n\\t\\t\\t\\t\\t2,\\\"Test message 2\\\"\\n\\t\\t\\t\\t\\t3,\\\"Test message 3\\\"\",\"source\":\"myforlist\"}}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {`\n\t\t\t\t\tData(src_test,\"type\"){\n\t\t\t\t\t\ttext\n\t\t\t\t\t}\n\t\t\t\t\tForList(src_test){\n\t\t\t\t\tIf(#type#==text){\n\t\t\t\t\t\tSpan(:#type#)\n\t\t\t\t\t}\n\t\t\t\t}`},\n\t\t\t},\n\t\t\t`[{\"tag\":\"data\",\"attr\":{\"columns\":[\"type\"],\"data\":[[\"text\"]],\"source\":\"src_test\",\"types\":[\"text\"]}},{\"tag\":\"forlist\",\"attr\":{\"source\":\"src_test\"},\"children\":[{\"tag\":\"span\",\"attr\":{\"\":\"text\"}}]}]`,\n\t\t},\n\t}\n\n\tvar ret contentResult\n\tfor _, v := range cases {\n\t\tassert.NoError(t, sendPost(v.url, &v.form, &ret))\n\t\tassert.Equal(t, v.expected, string(ret.Tree))\n\t}\n}\n"
  },
  {
    "path": "packages/api/context.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/golang-jwt/jwt/v4\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype contextKey int\n\nconst (\n\tcontextKeyLogger contextKey = iota\n\tcontextKeyToken\n\tcontextKeyClient\n)\n\nfunc setContext(r *http.Request, key, value any) *http.Request {\n\treturn r.WithContext(context.WithValue(r.Context(), key, value))\n}\n\nfunc getContext(r *http.Request, key any) any {\n\treturn r.Context().Value(key)\n}\n\nfunc setLogger(r *http.Request, log *log.Entry) *http.Request {\n\treturn setContext(r, contextKeyLogger, log)\n}\n\nfunc getLogger(r *http.Request) *log.Entry {\n\tif v := getContext(r, contextKeyLogger); v != nil {\n\t\treturn v.(*log.Entry)\n\t}\n\treturn nil\n}\n\nfunc setToken(r *http.Request, token *jwt.Token) *http.Request {\n\treturn setContext(r, contextKeyToken, token)\n}\n\nfunc getToken(r *http.Request) *jwt.Token {\n\tif v := getContext(r, contextKeyToken); v != nil {\n\t\treturn v.(*jwt.Token)\n\t}\n\treturn nil\n}\n\nfunc setClient(r *http.Request, client *Client) *http.Request {\n\treturn setContext(r, contextKeyClient, client)\n}\n\nfunc getClient(r *http.Request) *Client {\n\tif v := getContext(r, contextKeyClient); v != nil {\n\t\treturn v.(*Client)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/api/contract_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc init() {\n\tcrypto.InitAsymAlgo(\"ECC_Secp256k1\")\n\tcrypto.InitHashAlgo(\"KECCAK256\")\n}\nfunc TestBin(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tform := url.Values{`nowait`: {`nowait`}}\n\tassert.NoError(t, postTxMultipart(`@1NewContract`, &form))\n\t//_, _, err := postTxResult(\"rndPtlziReAis01638415503\", &url.Values{})\n\t//assert.NoError(t, err)\n}\n\nfunc TestTransferSelf(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tform := url.Values{`nowait`: {`nowait`}}\n\tassert.NoError(t, postTransferSelfTxMultipart(&form))\n\n}\n\nfunc TestUTXO(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tform := url.Values{`nowait`: {`nowait`}}\n\tassert.NoError(t, postUTXOTxMultipart(&form))\n\n}\n\nfunc TestMath(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tusers := []string{\n\t\t`04d750da3e19c5f7721a1dafd8663f2739dba23d81e01f0667730d217472a3bc9f93c6fbaade9c6b6387ece296c478d25559cb87ca3e58aa7ce627dd47ec902aea`,\n\t\t`0471f24f9dee904277a081df37377c4dbd7cc14671fec2f0c1a580a5d972c2f98d528ea7f460de8900ce70d6de08a118060f1a261b272722a460d87de93014f960`,\n\t\t`04df303174dfbc79b1e3baa196103c284b6ca97c21848511af18a401fdd1b0fb29bfd8724f43b44062ff5f67a969409ab037ae674a1010602b1a7d25245b49738c`,\n\t\t`044d92cd4f7f6bd3cb0c9600782d32797ebbc8a277a308b128f33453ed84f470e2bb88ceb5de87cd8288b8ade9e437c90de3610ddcfcfec41d6e70d302690bc3ec`,\n\t\t`04cbe75c40a2ef1256483c5bb910745171258b341f981598a01876fc3711c243f8fab181d72ea7abb838ad3f27e8a03b54032e8ab34656d9503539a38b05151cfa`,\n\t\t`04f220d6620b8a0ede8ac23e2724e467888138d654721fefb1a910bb717aaff279fed5560462ed7af1ac1208852822e73336033ce6289694a0d7dc974754cf61ae`,\n\t}\n\tfor _, u := range users {\n\t\tform := url.Values{\"NewPubkey\": {u}}\n\t\tassert.NoError(t, postTx(`@1NewUser`, &form))\n\t}\n\t//form := url.Values{`Value`: {`[{\"api_address\":\"http://127.0.0.1:7079\",\"public_key\":\"0498b18e551493a269b6f419d7784d26c8e3555638e80897c69997ef9f211e21d5d0b8adeeaab0e0e750e720ddf3048ec55d613ba5dee3fdfd4e7c17d346731e9b\",\"tcp_address\":\"127.0.0.1:7078\"},{\"tcp_address\":\"127.0.0.1:2078\",\"api_address\":\"http://127.0.0.1:2079\",\"public_key\":\"04d750da3e19c5f7721a1dafd8663f2739dba23d81e01f0667730d217472a3bc9f93c6fbaade9c6b6387ece296c478d25559cb87ca3e58aa7ce627dd47ec902aea\"},{\"tcp_address\":\"127.0.0.1:3078\",\"api_address\":\"http://127.0.0.1:3079\",\"public_key\":\"04df303174dfbc79b1e3baa196103c284b6ca97c21848511af18a401fdd1b0fb29bfd8724f43b44062ff5f67a969409ab037ae674a1010602b1a7d25245b49738c\"},{\"tcp_address\":\"127.0.0.1:4078\",\"api_address\":\"http://127.0.0.1:4079\",\"public_key\":\"04cbe75c40a2ef1256483c5bb910745171258b341f981598a01876fc3711c243f8fab181d72ea7abb838ad3f27e8a03b54032e8ab34656d9503539a38b05151cfa\"}]`}, \"Name\": {\"honor_nodes\"}, `Conditions`: {`true`}}\n\tform := url.Values{`Value`: {`[{\"api_address\":\"http://127.0.0.1:7079\",\"public_key\":\"0498b18e551493a269b6f419d7784d26c8e3555638e80897c69997ef9f211e21d5d0b8adeeaab0e0e750e720ddf3048ec55d613ba5dee3fdfd4e7c17d346731e9b\",\"tcp_address\":\"127.0.0.1:7078\"},{\"tcp_address\":\"127.0.0.1:2078\",\"api_address\":\"http://127.0.0.1:2079\",\"public_key\":\"04d750da3e19c5f7721a1dafd8663f2739dba23d81e01f0667730d217472a3bc9f93c6fbaade9c6b6387ece296c478d25559cb87ca3e58aa7ce627dd47ec902aea\"}]`}, \"Name\": {\"honor_nodes\"}, `Conditions`: {`true`}}\n\t//form := url.Values{`Value`: {`[{\"api_address\":\"http://127.0.0.1:7079\",\"public_key\":\"0498b18e551493a269b6f419d7784d26c8e3555638e80897c69997ef9f211e21d5d0b8adeeaab0e0e750e720ddf3048ec55d613ba5dee3fdfd4e7c17d346731e9b\",\"tcp_address\":\"127.0.0.1:7078\"},{\"tcp_address\":\"127.0.0.1:2078\",\"api_address\":\"http://127.0.0.1:2079\",\"public_key\":\"04d750da3e19c5f7721a1dafd8663f2739dba23d81e01f0667730d217472a3bc9f93c6fbaade9c6b6387ece296c478d25559cb87ca3e58aa7ce627dd47ec902aea\"},{\"tcp_address\":\"127.0.0.1:3078\",\"api_address\":\"http://127.0.0.1:3079\",\"public_key\":\"04df303174dfbc79b1e3baa196103c284b6ca97c21848511af18a401fdd1b0fb29bfd8724f43b44062ff5f67a969409ab037ae674a1010602b1a7d25245b49738c\"}]`}, \"Name\": {\"honor_nodes\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`@1UpdatePlatformParam`, &form))\n}\n\nfunc TestArray(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `@1rnd0Q3a3mIzpg01627469951`\n\tform := url.Values{`Info`: {crypto.RandSeq(14)}}\n\tassert.NoError(t, postTx(rnd, &form))\n}\n\nfunc TestCheckCondition(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `cnt` + crypto.RandSeq(4)\n\tform := url.Values{`Value`: {`contract ` + rnd + ` {\n    action {\n\t\t\t$result = Sprintf(\"%v %v %v %v %v\", CheckCondition(\"1\"), CheckCondition(\"0\"), \n\t\t\t\t\tCheckCondition(\"ContractConditions(\\\"MainCondition\\\")\"), CheckCondition(\"true\"), \n\t\t\t\t\tCheckCondition(\"false\"))\n    }\n}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\t_, msg, err := postTxResult(rnd, &url.Values{})\n\tassert.NoError(t, err)\n\tif msg != `true false true true false` {\n\t\tt.Error(fmt.Errorf(`wrong msg %s`, msg))\n\t}\n}\n\nfunc TestDBFindContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `db` + crypto.RandSeq(4)\n\tform := url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\tdata {\n\t\t}\n\t\taction { \n\t\t\tvar fm array\n\t\t\tfm = DBFind(\"@1contracts\").Where({\"ecosystem\": $ecosystem_id, \n\t\t\t   \"app_id\": 1, ,\"id\": {\"$gt\": 2}})\n\t\t\t$result = Len(fm)\n\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.EqualError(t, postTx(`NewContract`, &form),\n\t\t`{\"type\":\"panic\",\"error\":\"unexpected lexeme; expecting string key [CreateContract @1NewContract:32]\"}`)\n\tform = url.Values{`Value`: {`contract ` + rnd + `2 {\n\t\t\t\tdata {\n\t\t\t\t}\n\t\t\t\taction {\n\t\t\t\t\tvar fm array\n\t\t\t\t\tfm = DBFind(\"@1contracts\").Where({\"ecosystem\": $ecosystem_id,\n\t\t\t\t\t   \"app_id\": 1,\"id\": {\"$gt\": 2},})\n\t\t\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.EqualError(t, postTx(`NewContract`, &form),\n\t\t`{\"type\":\"panic\",\"error\":\"unexpected lexeme; expecting string key [CreateContract @1NewContract:32]\"}`)\n\tform = url.Values{`Value`: {`contract ` + rnd + `3 {\n\t\t\tdata {\n\t\t\t}\n\t\t\taction { \n\t\t\t\tvar fm array\n\t\t\t\tfm = [1, 2, 3,]\n\t\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.EqualError(t, postTx(`NewContract`, &form),\n\t\t`{\"type\":\"panic\",\"error\":\"unexpected lexeme; expecting string, int value or variable [CreateContract @1NewContract:32]\"}`)\n\n\tform = url.Values{`Value`: {`contract ` + rnd + ` {\n\t   \t\t    data {\n\t   \t\t\t}\n\t   \t\t\taction {\n\t   \t\t\t\tvar ret i j k m array\n\t   \t\t\t\tvar inr inc map\n\t   \t\t\t\tvar rids array\n\t                   rids = JSONDecode(\"[]\")//role[\"roles_access\"])\n\t   \t\t\t\tinr = DBFind(\"@1roles_participants\").Where({\"ecosystem\": $ecosystem_id, \"role->id\": {\"$in\": rids}, \"member->member_id\": $key_id, \"deleted\": 0}).Row()\n\t   \t\t\t\tinc = DBFind(\"contracts\").Where({\"ecosystem\": $ecosystem_id, \"id\": {\"$in\": rids}}).Row()\n\t   \t\t\t\tret = DBFind(\"contracts\").Where({value: {\"$ibegin\": \"CONTRACT\"}}).Limit(100)\n\t   \t\t\t\ti = DBFind(\"contracts\").Where({value: {$ilike: \"rEmove\"}}).Limit(100)\n\t   \t\t\t\tj = DBFind(\"contracts\").Where({id: {$lt: 10}})\n\t   \t\t\t\tk = DBFind(\"contracts\").Where({id: {$lt: 11}, $or: [{id: 5}, {id: 7}], $and: [{id: {$neq: 25}}, id: {$neq: 26} ]})\n\t   \t\t\t\tm = DBFind(\"contracts\").Where({id: 10, name: \"EditColumn\", $or: [id: 10, id: {$neq: 20}]})\n\t   \t\t\t\t$result = Sprintf(\"%d %d %d %d %d\", Len(ret), Len(i), Len(j), Len(k), Len(m))\n\t   \t\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\t_, msg, err := postTxResult(rnd, &url.Values{})\n\tassert.NoError(t, err)\n\tif msg != `25 25 9 2 1` {\n\t\tt.Error(fmt.Errorf(`wrong msg %s`, msg))\n\t}\n}\n\nfunc TestErrorContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `err` + crypto.RandSeq(4)\n\tform := url.Values{`Value`: {`contract ` + rnd + ` {\n\t\t    data {\n\t\t\t}\n\t\t\taction { \n\t\t\t\terror(\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce tincidunt \n\t\t\t\tvestibulum eros. Curabitur fermentum pulvinar nibh, in maximus dolor tempor quis. \n\t\t\t\tDonec non nulla id ex lacinia bibendum eu a sapien. Nam eu mi feugiat, gravida \n\t\t\t\terat ac, tincidunt dolor. Curabitur sed erat et felis turpis duis.\")\n\t\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\t_, _, err := postTxResult(rnd, &url.Values{})\n\tif len(err.Error()) > 250 {\n\t\tt.Error(`Too long error`)\n\t}\n\trnd += `1`\n\tform = url.Values{`Value`: {`contract ` + rnd + ` {\n\t\tdata {\n\t\t}\n\t\taction { \n\t\t\tThrow(\"This is a problem\", \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce tincidunt \n\t\t\tvestibulum eros. Curabitur fermentum pulvinar nibh, in maximus dolor tempor quis. \n\t\t\tDonec non nulla id ex lacinia bibendum eu a sapien. Nam eu mi feugiat, gravida \n\t\t\terat ac, tincidunt dolor. Curabitur sed erat et felis turpis duis.\")\n\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\t_, _, err = postTxResult(rnd, &url.Values{})\n\tif len(err.Error()) > 250 {\n\t\tt.Error(`Too long error`)\n\t}\n}\n\nfunc TestUpdate_HonorNodes(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr := postTx(\"UpdatePlatformParam\", &url.Values{\n\t\t\"Name\":  {\"honor_nodes\"},\n\t\t\"Value\": {\"[]\"},\n\t})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestCrashContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `crash` + crypto.RandSeq(4)\n\tform := url.Values{`Value`: {`contract ` + rnd + ` {\n\t\t\tdata {}\n\t\t\n\t\t\tconditions {\n\t\t\t\t$Recipient = Append([], \"1\")\n\t\t\t\t$Recipient = Append($Recipient, \"7\")\n\t\t\t}\n\t\t\n\t\t\taction {\n\t\t\t\tvar i int\n\t\t\t\tvar steps map\n\t\t\t\tvar list myarr q b array\n\t\t\t\twhile i < Len($Recipient) {\n\t\t\t\t\tsteps[\"recipient_role\"] = JSONDecode($Recipient[i])\n\t\t\t\t\tlist[i] = Append(list, steps)\n\t\t\t\t\tmyarr = Split(list[i], \",\")\n\t\t\t\t\ti = i + 1\n\t\t\t\t}\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(rnd, &url.Values{}), `{\"type\":\"panic\",\"error\":\"self assignment\"}`)\n}\n\nfunc TestHardContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `hard` + crypto.RandSeq(4)\n\tform := url.Values{`Value`: {`contract ` + rnd + ` {\n\t\t    data {\n\t\t\t}\n\t\t\taction { \n\t\t\t\tvar i int\n\t\t\t\twhile i < 500 {\n\t\t\t\t DBFind(\"pages\").Where({id:5})\n\t\t\t\t DBUpdate(\"pages\", 5, {\"value\":\"P(text)\"})\n\t\t\t\t DBInsert(\"pages\", {\"name\": Sprintf(\"` + rnd + `%d\", i),\n\t\t\t\t      \"value\":\"P(text)\", \"conditions\": \"true\"})\n\t\t\t\t DBFind(\"pages\").Where({id:6})\n\t\t\t\t DBFind(\"pages\").Where({id:7})\n\t\t\t\t DBUpdate(\"pages\", 6, {\"value\": \"P(text)\"})\n\t\t\t\t i = i + 1\n\t\t\t   }\n\t\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(rnd, &url.Values{}), `{\"type\":\"txError\",\"error\":\"Time limit exceeded\"}`)\n}\n\nfunc TestExistContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\trnd := `cnt` + crypto.RandSeq(4)\n\tform := url.Values{\"Name\": {rnd}, \"Value\": {`contract ` + rnd + ` {\n\t\tdata {\n\t\t\tName string\n\t\t}\n\t\taction {\n\t\tThrow($Name, \"Text of the error\")\n\t}}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tassert.EqualError(t, postTx(rnd, &url.Values{\"Name\": {\"1\"}}),\n\t\t`{\"type\":\"exception\",\"error\":\"Text of the error\",\"id\":\"1\"}`)\n\tform = url.Values{\"Name\": {`EditPage`}, \"Value\": {`contract EditPage {action {}}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\n\tassert.EqualError(t, postTx(`NewContract`, &form), `{\"type\":\"panic\",\"error\":\"Contract EditPage already exists\"}`)\n}\n\nfunc TestDataContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tname := `cnt` + crypto.RandSeq(4)\n\tform := url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `1 {\n\t\tdata {Name int\n\t\t\tstring qwerty}\n\t\taction {}\n\t\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.EqualError(t, postTx(`NewContract`, &form), `{\"type\":\"panic\",\"error\":\"expecting name of the data field [Ln:3 Col:5]\"}`)\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\tdata {MyApp qwerty}\n\t\taction {}\n\t\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.EqualError(t, postTx(`NewContract`, &form), `{\"type\":\"panic\",\"error\":\"expecting type of the data field [Ln:2 Col:16]\"}`)\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\tdata {MyApp int\n\t\t    Qwert}\n\t\taction {}\n\t\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.EqualError(t, postTx(`NewContract`, &form), `{\"type\":\"panic\",\"error\":\"expecting type of the data field [Ln:3 Col:13]\"}`)\n}\n\nfunc TestTypesContract(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tname := `cnt` + crypto.RandSeq(4)\n\tform := url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\tdata {\n\t\t\tFloat float\n\t\t\tAddr  address\n\t\t\tArr   array\n\t\t\tMap   map\n\t\t}\n\t\taction { $result = Sprintf(\"%v=%v=%v=%v\", $Float, $Addr, $Arr, $Map) }\n\t\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\t_, msg, err := postTxResult(name, &url.Values{\"Float\": {\"1.23\"}, \"Addr\": {\"-1334343423\"},\n\t\t\"Arr\": {`[23,\"tt\"]`}, \"Map\": {`{\"k\" : \"v\"}`}})\n\tassert.NoError(t, err)\n\tif msg != `1.23=-1334343423=[23 tt]=map[k:v]` {\n\t\tt.Error(`Wrong msg`, msg)\n\t}\n}\n\nfunc TestNewContracts(t *testing.T) {\n\n\t//wanted := func(name, want string) bool {\n\t//\tvar ret getTestResult\n\t//\treturn assert.NoError(t, sendPost(`test/`+name, nil, &ret)) && assert.Equal(t, want, ret.Value)\n\t//}\n\n\tassert.NoError(t, keyLogin(1))\n\trnd := crypto.RandSeq(4)\n\tfor i, item := range contracts {\n\t\tvar ret getContractResult\n\t\tif i > 100 {\n\t\t\tbreak\n\t\t}\n\t\tname := strings.Replace(item.Name, `#rnd#`, rnd, -1)\n\t\terr := sendGet(`contract/`+name, nil, &ret)\n\t\tif err != nil {\n\t\t\tif strings.Contains(err.Error(), errContract.Errorf(name).Error()) {\n\t\t\t\tform := url.Values{\"Name\": {name}, \"Value\": {strings.Replace(item.Value,\n\t\t\t\t\t`#rnd#`, rnd, -1)},\n\t\t\t\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\t\t\t\tif err := postTx(`NewContract`, &form); err != nil {\n\t\t\t\t\tassert.EqualError(t, err, item.Params[0].Results[`error`])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif strings.HasSuffix(name, `testUpd`) {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, par := range item.Params {\n\t\t\tform := url.Values{}\n\t\t\tfor key, value := range par.Params {\n\t\t\t\tform[key] = []string{value}\n\t\t\t}\n\t\t\tif err := postTx(name, &form); err != nil {\n\t\t\t\tassert.EqualError(t, err, par.Results[`error`])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t//for key, value := range par.Results {\n\t\t\t//\tif !wanted(key, value) {\n\t\t\t//\t\treturn\n\t\t\t//\t}\n\t\t\t//}\n\t\t}\n\t}\n\tvar row rowResult\n\tassert.NoError(t, sendGet(`row/menu/1`, nil, &row))\n\tassert.NotEqual(t, `update`, row.Value[`value`])\n}\n\nvar contracts = []smartContract{\n\t{`Empty`, `contract Empty {\n\t\taction {\n\t\t\tvar a1 array\n\t\t\tvar a2 map\n\t\t\t$a1 = []\n\t\t\t$a2 = {}\n\t\t\tTest(\"result\", \"ok\")\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`result`: `ok`}},\n\t}},\n\n\t{`FmtMoney`, `contract FmtMoney {\n\t\taction {\n\t\t\tTest(\"result\", FormatMoney(\"123456789\", 0))\n\t\t\t$num2 = \"5500000\"\n\t\t\t$num1 = \"12345672372\"\n\t\t\tTest(\"t1\", FormatMoney($num1, -1))  //123456723720\n\t\t\tTest(\"t2\", FormatMoney($num1, 0))   //12345672372\n\t\t\tTest(\"t3\", FormatMoney($num1, 1))   //1234567237,2\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`result`: `123456789`,\n\t\t\t`t1`: `123456723720`, `t2`: `12345672372`, `t3`: `1234567237.2`}},\n\t}},\n\n\t{`StrNil`, `contract StrNil {\n\t\taction {\n\t\t\tTest(\"result\", Sprintf(\"empty: %s\", Str(nil)))\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`result`: `empty: `}},\n\t}},\n\t{`TestJSON`, `contract TestJSON {\n\t\tdata {}\n\t\tconditions { }\n\t\taction {\n\t\t   var a map\n\t\t   a[\"ok\"] = 10\n\t\t   a[\"arr\"] = [\"first\", \"<second>\"]\n\t\t   Test(\"json\", JSONEncode(a))\n\t\t   Test(\"ok\", JSONEncodeIndent(a, \"\\t\"))\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`ok`: \"{\\n\\t\\\"ok\\\": 10,\\n\\t\\\"arr\\\": [\\n\\t\\t\\\"first\\\",\\n\\t\\t\\\"<second>\\\"\\n\\t]\\n}\",\n\t\t\t`json`: \"{\\\"ok\\\":10,\\\"arr\\\":[\\\"first\\\",\\\"<second>\\\"]}\"}},\n\t}},\n\t{`GuestKey`, `contract GuestKey {\n\t\taction {\n\t\t\tTest(\"result\", $guest_key)\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`result`: `4544233900443112470`}},\n\t}},\n\t{`TestCyr`, `contract TestCyr {\n\t\tdata {}\n\t\tconditions { }\n\t\taction {\n\t\t   //test\n\t\t   var a map\n\t\t   a[\"test\"] = \"test\"\n\t\t   Test(\"ok\", a[\"test\"])\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`ok`: `test`}},\n\t}},\n\t{`DBFindLike`, `contract DBFindLike {\n\t\taction {\n\t\t\tvar list array\n\t\t\tlist = DBFind(\"pages\").Where({\"name\":{\"$like\": \"ort_\"}})\n\t\t\tTest(\"size\", Len(list))\n\t\t\tlist = DBFind(\"pages\").Where({\"name\":{\"$end\": \"page\"}})\n\t\t\tTest(\"end\", Len(list))\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`size`: `4`, `end`: `2`}},\n\t}},\n\t{`TestDBFindOK`, `\n\t\t\tcontract TestDBFindOK {\n\t\t\taction {\n\t\t\t\tvar ret array\n\t\t\t\tvar vals map\n\t\t\t\tret = DBFind(\"contracts\").Columns(\"id,value\").Where({\"$and\":[{\"id\":{\"$gte\": 3}}, {\"id\":{\"$lte\":5}}]}).Order(\"id\")\n\t\t\t\tif Len(ret) {\n\t\t\t\t\tTest(\"0\",  \"1\")\n\t\t\t\t} else {\n\t\t\t\t\tTest(\"0\",  \"0\")\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").Limit(3)\n\t\t\t\tif Len(ret) == 3 {\n\t\t\t\t\tTest(\"1\",  \"1\")\n\t\t\t\t} else {\n\t\t\t\t\tTest(\"1\",  \"0\")\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").Order(\"id\").Offset(1).Limit(1)\n\t\t\t\tif Len(ret) != 1 {\n\t\t\t\t\tTest(\"2\",  \"0\")\n\t\t\t\t} else {\n\t\t\t\t\tvals = ret[0]\n\t\t\t\t\tTest(\"2\",  vals[\"id\"])\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").Columns(\"id\").Order([\"id\"]).Offset(1).Limit(1)\n\t\t\t\tif Len(ret) != 1 {\n\t\t\t\t\tTest(\"3\",  \"0\")\n\t\t\t\t} else {\n\t\t\t\t\tvals = ret[0]\n\t\t\t\t\tTest(\"3\", vals[\"id\"])\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").Columns(\"id\").Where({\"$or\":[{\"id\": \"1\"}]})\n\t\t\t\tif Len(ret) != 1 {\n\t\t\t\t\tTest(\"4\",  \"0\")\n\t\t\t\t} else {\n\t\t\t\t\tvals = ret[0]\n\t\t\t\t\tTest(\"4\", vals[\"id\"])\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").Columns(\"id\").Where({\"id\": 1})\n\t\t\t\tif Len(ret) != 1 {\n\t\t\t\t\tTest(\"4\",  \"0\")\n\t\t\t\t} else {\n\t\t\t\t\tvals = ret[0]\n\t\t\t\t\tTest(\"4\", vals[\"id\"])\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").Columns(\"id,value\").Where({\"id\":[{\"$gt\":3},{\"$lt\":8}]}).Order([{\"id\": 1}, {\"name\": \"-1\"}])\n\t\t\t\tif Len(ret) != 4 {\n\t\t\t\t\tTest(\"5\",  \"0\")\n\t\t\t\t} else {\n\t\t\t\t\tvals = ret[0]\n\t\t\t\t\tTest(\"5\", vals[\"id\"])\n\t\t\t\t}\n\t\t\t\tret = DBFind(\"contracts\").WhereId(7)\n\t\t\t\tif Len(ret) != 1 {\n\t\t\t\t\tTest(\"6\",  \"0\")\n\t\t\t\t} else {\n\t\t\t\t\tvals = ret[0]\n\t\t\t\t\tTest(\"6\", vals[\"id\"])\n\t\t\t\t}\n\t\t\t\tvar one string\n\t\t\t\tone = DBFind(\"contracts\").WhereId(5).One(\"id\")\n\t\t\t\tTest(\"7\",  one)\n\t\t\t\tvar row map\n\t\t\t\trow = DBFind(\"contracts\").WhereId(3).Row()\n\t\t\t\tTest(\"8\",  row[\"id\"])\n\t\t\t\tTest(\"255\",  \"255\")\n\t\t\t}\n\t\t}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`0`: `1`, `1`: `1`, `2`: `2`, `3`: `2`, `4`: `1`, `5`: `4`,\n\t\t\t\t`6`: `7`, `7`: `5`, `8`: `3`, `255`: `255`}},\n\t\t}},\n\t{`DBFindCol`, `contract DBFindCol {\n\t\taction {\n\t\t\tvar ret string\n\t\t\tret = DBFind(\"keys\").Columns([\"amount\", \"id\"]).One(\"amount\")\n\t\t\tTest(\"size\", Size(ret)>0)\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`size`: `true`}},\n\t}},\n\t{`DBFindColumnNow`, `contract DBFindColumnNow {\n\t\taction {\n\t\t\tvar list array\n\t\t\tlist = DBFind(\"keys\").Columns(\"now()\")\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"pq: current transaction is aborted, commands ignored until end of transaction block\"}`}},\n\t}},\n\t{`DBFindCURRENT`, `contract DBFindCURRENT {\n\t\taction {\n\t\t\tvar list array\n\t\t\tlist = DBFind(\"mytable\").Where({\"date\": {\"$lt\": \"CURRENT_DATE\"}})\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"It is prohibited to use NOW() or current time functions\"}`}},\n\t}},\n\t{`RowType`, `contract RowType {\n\taction {\n\t\tvar app map\n\t\tvar result string\n\t\tresult = GetType(app)\n\t\tapp = DBFind(\"applications\").Where({\"id\":\"1\"}).Row()\n\t\tresult = result + GetType(app)\n\t\tapp[\"app_id\"] = 2\n\t\tTest(\"result\", Sprintf(\"%s %s %d\", result, app[\"name\"], app[\"app_id\"]))\n\t}\n}`, []smartParams{\n\t\t{nil, map[string]string{`result`: `*types.Map*types.Map System 2`}},\n\t}},\n\t{`StackType`, `contract StackType {\n\t\taction {\n\t\t\tvar lenStack int\n\t\t\tlenStack = Len($stack)\n\t\t\tvar par string\n\t\t\tpar = $stack[0]\n\t\t\tTest(\"result\", Sprintf(\"len=%d %v %s\", lenStack, $stack, par))\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`result`: `len=1 [@1StackType] @1StackType`}},\n\t}},\n\t{`DBFindNow`, `contract DBFindNow {\n\t\taction {\n\t\t\tvar list array\n\t\t\tlist = DBFind(\"mytable\").Where({\"date\": {\"$lt\": \"now ( )\"}})\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"It is prohibited to use NOW() or current time functions\"}`}},\n\t}},\n\t{`BlockTimeCheck`, `contract BlockTimeCheck {\n\t\taction {\n\t\t\tif Size(BlockTime()) == Size(\"2006-01-02 15:04:05\") {\n\t\t\t\tTest(\"ok\", \"1\")\n\t\t\t} else {\n\t\t\t\tTest(\"ok\", \"0\")\n\t\t\t}\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`ok`: `1`}},\n\t}},\n\t{`RecCall`, `contract RecCall {\n\t\tdata {    }\n\t\tconditions {    }\n\t\taction {\n\t\t\tvar par map\n\t\t\tCallContract(\"RecCall\", par)\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"There is loop in @1RecCall contract\"}`}},\n\t}},\n\t{`Recursion`, `contract Recursion {\n\t\tdata {    }\n\t\tconditions {    }\n\t\taction {\n\t\t\tRecursion()\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"The contract can't call itself recursively\"}`}},\n\t}},\n\t{`MyTable#rnd#`, `contract MyTable#rnd# {\n\t\taction {\n\t\t\tNewTable(\"Name,Columns,ApplicationId,Permissions\", \"#rnd#1\", \n\t\t\t\t\"[{\\\"name\\\":\\\"MyName\\\",\\\"type\\\":\\\"varchar\\\", \\\"index\\\": \\\"0\\\", \\\"conditions\\\":{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"true\\\"}}]\", 100,\n\t\t\t\t \"{\\\"insert\\\": \\\"true\\\", \\\"update\\\" : \\\"true\\\", \\\"new_column\\\": \\\"true\\\"}\")\n\t\t\tvar cols array\n\t\t\tcols[0] = \"{\\\"conditions\\\":\\\"true\\\",\\\"name\\\":\\\"column1\\\",\\\"type\\\":\\\"text\\\"}\"\n\t\t\tcols[1] = \"{\\\"conditions\\\":\\\"true\\\",\\\"name\\\":\\\"column2\\\",\\\"type\\\":\\\"text\\\"}\"\n\t\t\tNewTable(\"Name,Columns,ApplicationId,Permissions\", \"#rnd#2\", \n\t\t\t\tJSONEncode(cols), 100,\n\t\t\t\t \"{\\\"insert\\\": \\\"true\\\", \\\"update\\\" : \\\"true\\\", \\\"new_column\\\": \\\"true\\\"}\")\n\t\t\t\n\t\t\tTest(\"ok\", \"1\")\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`ok`: `1`}},\n\t}},\n\t{`IntOver`, `contract IntOver {\n\t\t\t\taction {\n\t\t\t\t\tinfo Int(\"123456789101112131415161718192021222324252627282930\")\n\t\t\t\t}\n\t\t\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"123456789101112131415161718192021222324252627282930 is not a valid integer : value out of range\"}`}},\n\t}},\n\t{`Double`, `contract Double {\n\t\tdata {    }\n\t\tconditions {    }\n\t\taction {\n\t\t\t$$$$$$$$result = \"hello\"\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"unknown lexeme $ [Ln:5 Col:6]\"}`}},\n\t}},\n\t{`Price`, `contract Price {\n\t\taction {\n\t\t\tTest(\"int\", Int(\"\")+Int(nil)+2)\n\t\t\tTest(\"price\", 1)\n\t\t}\n\t\tfunc price() money {\n\t\t\treturn Money(100)\n\t\t}\n\t}`, []smartParams{\n\t\t{nil, map[string]string{`price`: `1`, `int`: `2`}},\n\t}},\n\t{`CheckFloat`, `contract CheckFloat {\n\t\t\taction {\n\t\t\tvar fl float\n\t\t\tfl = -3.67\n\t\t\tTest(\"float2\", Sprintf(\"%d %s\", Int(1.2), Str(fl)))\n\t\t\tTest(\"float3\", Sprintf(\"%.2f %.2f\", 10.7/7, 10/7.0))\n\t\t\tTest(\"float4\", Sprintf(\"%.2f %.2f %.2f\", 10+7.0, 10-3.1, 5*2.5))\n\t\t\tTest(\"float5\", Sprintf(\"%t %t %t %t %t\", 10 <= 7.0, 4.5 <= 5, 3>5.7, 6 == 6.0, 7 != 7.1))\n\t\t}}`, []smartParams{\n\t\t{nil, map[string]string{`float2`: `1 -3.670000`, `float3`: `1.53 1.43`, `float4`: `17.00 6.90 12.50`, `float5`: `false true false true true`}},\n\t}},\n\t{`Crash`, `contract Crash { data {} conditions {} action\n\n\t\t\t{ $result=DBUpdate(\"menu\", 1, {\"value\": \"updated\"}) }\n\t\t\t}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"Access denied\"}`}},\n\t\t}},\n\t{`TestOneInput`, `contract TestOneInput {\n\t\t\tdata {\n\t\t\t\tlist array\n\t\t\t}\n\t\t\taction {\n\t\t\t\tvar coltype string\n\t\t\t\tcoltype = GetColumnType(\"keys\", \"amount\" )\n\t\t\t\tTest(\"oneinput\",  $list[0]+coltype)\n\t\t\t}\n\t\t}`,\n\t\t[]smartParams{\n\t\t\t{map[string]string{`list`: `Input value`}, map[string]string{`oneinput`: `Input valuemoney`}},\n\t\t}},\n\t{`DBProblem`, `contract DBProblem {\n\t\taction{\n\t\t\tDBFind(\"members1\").Where({\"member_name\": \"name\"})\n\t\t}\n\t}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"pq: current transaction is aborted, commands ignored until end of transaction block\"}`}},\n\t\t}},\n\t{`TestMultiForm`, `contract TestMultiForm {\n\t\t\t\tdata {\n\t\t\t\t\tlist array\n\t\t\t\t}\n\t\t\t\taction {\n\t\t\t\t\tTest(\"multiform\",  $list[0]+$list[1])\n\t\t\t\t}\n\t\t\t}`,\n\t\t[]smartParams{\n\t\t\t{map[string]string{`list[]`: `2`, `list[0]`: `start`, `list[1]`: `finish`}, map[string]string{`multiform`: `startfinish`}},\n\t\t}},\n\t{`errTestMessage`, `contract errTestMessage {\n\t\t\tconditions {\n\t\t\t}\n\t\t\taction { qvar ivar int}\n\t\t}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`error`: `{\"type\":\"panic\",\"error\":\"unknown variable qvar\"}`}},\n\t\t}},\n\n\t{`EditProfile9`, `contract EditProfile9 {\n\t\t\tdata {\n\t\t\t}\n\t\t\tconditions {\n\t\t\t}\n\t\t\taction {\n\t\t\t\tvar ar array\n\t\t\t\tar = Split(\"point 1,point 2\", \",\")\n\t\t\t\tTest(\"split\",  Str(ar[1]))\n\t\t\t\t$ret = DBFind(\"contracts\").Columns(\"id,value\").Where({\"id\":[{\"$gte\": 3}, {\"$lte\":5}]}).Order(\"id\")\n\t\t\t\tTest(\"edit\",  \"edit value 0\")\n\t\t\t}\n\t\t}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`edit`: `edit value 0`, `split`: `point 2`}},\n\t\t}},\n\t{`testEmpty`, `contract testEmpty {\n\t\t\t\t\taction { Test(\"empty\",  \"empty value\")}}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`empty`: `empty value`}},\n\t\t}},\n\t{`testUpd`, `contract testUpd {\n\t\t\t\t\t\taction { Test(\"date\",  \"-2006.01.02-\")}}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`date`: `-` + time.Now().Format(`2006.01.02`) + `-`}},\n\t\t}},\n\t{`testLong`, `contract testLong {\n\t\t\taction { Test(\"long\",  \"long result\")\n\t\t\t\t$result = DBFind(\"contracts\").WhereId(2).One(\"value\") + DBFind(\"contracts\").WhereId(4).One(\"value\")\n\t\t\t\tPrintln(\"Result\", $result)\n\t\t\t\tTest(\"long\",  \"long result\")\n\t\t\t}}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`long`: `long result`}},\n\t\t}},\n\t{`testSimple`, `contract testSimple {\n\t\t\t\t\tdata {\n\t\t\t\t\t\tAmount int\n\t\t\t\t\t\tName   string\n\t\t\t\t\t}\n\t\t\t\t\tconditions {\n\t\t\t\t\t\tTest(\"scond\", $Amount, $Name)\n\t\t\t\t\t}\n\t\t\t\t\taction { Test(\"sact\", $Name, $Amount)}}`,\n\t\t[]smartParams{\n\t\t\t{map[string]string{`Name`: `Simple name`, `Amount`: `-56781`},\n\t\t\t\tmap[string]string{`scond`: `-56781Simple name`,\n\t\t\t\t\t`sact`: `Simple name-56781`}},\n\t\t}},\n\t{`errTestVar`, `contract errTestVar {\n\t\t\t\tconditions {\n\t\t\t\t}\n\t\t\t\taction { var ivar int}\n\t\t\t}`,\n\t\tnil},\n\t{`testGetContract`, `contract testGetContract {\n\t\t\taction { Test(\"ByName\", GetContractByName(\"\"), GetContractByName(\"ActivateContract\"))\n\t\t\t\tTest(\"ById\", GetContractById(10000000), GetContractById(16))}}`,\n\t\t[]smartParams{\n\t\t\t{nil, map[string]string{`ByName`: `0 4`,\n\t\t\t\t`ById`: `EditTable`}},\n\t\t}},\n\t{\n\t\t`testDateTime`, `contract testDateTime {\n\t\t\t\tdata {\n\t\t\t\t\tDate string\n\t\t\t\t\tUnix int\n\t\t\t\t}\n\t\t\t\taction {\n\t\t\t\t\tTest(\"DateTime\", DateTime($Unix))\n\t\t\t\t\tTest(\"UnixDateTime\", UnixDateTime($Date))\n\t\t\t\t}\n\t\t\t}`,\n\t\t[]smartParams{\n\t\t\t{map[string]string{\n\t\t\t\t\"Unix\": \"1257894000\",\n\t\t\t\t\"Date\": \"2009-11-11 04:00:00\",\n\t\t\t}, map[string]string{\n\t\t\t\t\"DateTime\":     \"2009-11-11 04:00:00\",\n\t\t\t\t\"UnixDateTime\": timeMustParse(\"2009-11-11 04:00:00\"),\n\t\t\t}},\n\t\t},\n\t},\n}\n\nfunc timeMustParse(value string) string {\n\tt, _ := time.Parse(\"2006-01-02 15:04:05\", value)\n\treturn converter.Int64ToStr(t.Unix())\n}\n\nfunc TestEditContracts(t *testing.T) {\n\n\t//wanted := func(name, want string) bool {\n\t//\tvar ret getTestResult\n\t//\terr := sendPost(`test/`+name, nil, &ret)\n\t//\tif err != nil {\n\t//\t\tt.Error(err)\n\t//\t\treturn false\n\t//\t}\n\t//\tif ret.Value != want {\n\t//\t\tt.Error(fmt.Errorf(`%s != %s`, ret.Value, want))\n\t//\t\treturn false\n\t//\t}\n\t//\treturn true\n\t//}\n\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar cntlist contractsResult\n\terr := sendGet(`contracts`, nil, &cntlist)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret getContractResult\n\terr = sendGet(`contract/testUpd`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tsid := ret.TableID\n\tvar row rowResult\n\terr = sendGet(`row/contracts/`+sid, nil, &row)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tcode := row.Value[`value`]\n\toff := strings.IndexByte(code, '-')\n\tnewCode := code[:off+1] + time.Now().Format(`2006.01.02`) + code[off+11:]\n\tform := url.Values{`Id`: {sid}, `Value`: {newCode}, `Conditions`: {row.Value[`conditions`]}, `WalletId`: {\"01231234123412341230\"}}\n\tif err := postTx(`EditContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tfor _, item := range contracts {\n\t\tif !strings.HasSuffix(item.Name, `testUpd`) {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, par := range item.Params {\n\t\t\tform := url.Values{}\n\t\t\tfor key, value := range par.Params {\n\t\t\t\tform[key] = []string{value}\n\t\t\t}\n\t\t\tif err := postTx(item.Name, &form); err != nil {\n\t\t\t\tt.Error(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t//for key, value := range par.Results {\n\t\t\t//\tif !wanted(key, value) {\n\t\t\t//\t\treturn\n\t\t\t//\t}\n\t\t\t//}\n\t\t}\n\t}\n}\n\nfunc TestNewTableWithEmptyName(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\tsql1 := `new_column varchar(10); update block_chain set key_id='1234' where id='1' --`\n\tsql2 := `new_column varchar(10); update block_chain set key_id='12' where id='1' --`\n\tname := randName(`tbl`)\n\tform := url.Values{\n\t\t\"Name\":          {name},\n\t\t\"Columns\":       {\"[{\\\"name\\\":\\\"\" + sql1 + \"\\\",\\\"type\\\":\\\"varchar\\\", \\\"index\\\": \\\"0\\\", \\\"conditions\\\":{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"true\\\"}}]\"},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Permissions\":   {\"{\\\"insert\\\": \\\"true\\\", \\\"update\\\" : \\\"true\\\", \\\"new_column\\\": \\\"true\\\"}\"},\n\t}\n\n\trequire.NoError(t, postTx(\"NewTable\", &form))\n\n\tform = url.Values{\"TableName\": {name}, \"Name\": {sql2},\n\t\t\"Type\": {\"varchar\"}, \"Index\": {\"0\"}, \"Permissions\": {\"true\"}}\n\tassert.NoError(t, postTx(`NewColumn`, &form))\n\n\tform = url.Values{\n\t\t\"Name\":          {\"\"},\n\t\t\"Columns\":       {\"[{\\\"name\\\":\\\"MyName\\\",\\\"type\\\":\\\"varchar\\\", \\\"index\\\": \\\"0\\\", \\\"conditions\\\":{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"true\\\"}}]\"},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Permissions\":   {\"{\\\"insert\\\": \\\"true\\\", \\\"update\\\" : \\\"true\\\", \\\"new_column\\\": \\\"true\\\"}\"},\n\t}\n\n\tif err := postTx(\"NewTable\", &form); err == nil || err.Error() !=\n\t\t`400 {\"error\": \"E_SERVER\", \"msg\": \"Name is empty\" }` {\n\t\tt.Error(`wrong error`, err)\n\t}\n\n\tform = url.Values{\n\t\t\"Name\":          {\"Digit\" + name},\n\t\t\"Columns\":       {\"[{\\\"name\\\":\\\"1\\\",\\\"type\\\":\\\"varchar\\\", \\\"index\\\": \\\"0\\\", \\\"conditions\\\":{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"true\\\"}}]\"},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Permissions\":   {\"{\\\"insert\\\": \\\"true\\\", \\\"update\\\" : \\\"true\\\", \\\"new_column\\\": \\\"true\\\"}\"},\n\t}\n\n\tassert.EqualError(t, postTx(\"NewTable\", &form), `{\"type\":\"panic\",\"error\":\"Column name cannot begin with digit\"}`)\n}\n\nfunc TestContracts(t *testing.T) {\n\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tvar ret contractsResult\n\terr := sendGet(`contracts`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestSignature(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(6)\n\tform := url.Values{`Value`: {`contract ` + rnd + `Transfer {\n\t\t    data {\n\t\t\t\tRecipient int\n\t\t\t\tAmount    money\n\t\t\t\tSignature string \"optional hidden\"\n\t\t\t}\n\t\t\taction { \n\t\t\t\t$result = \"OK \" + Str($Amount)\n\t\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tif err := postTx(`NewContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract ` + rnd + `Test {\n\t\t\tdata {\n\t\t\t\tRecipient int \"hidden\"\n\t\t\t\tAmount  money\n\t\t\t\tSignature string \"signature:` + rnd + `Transfer\"\n\t\t\t}\n\t\t\tfunc action {\n\t\t\t\t` + rnd + `Transfer(\"Recipient,Amount,Signature\",$Recipient,$Amount,$Signature )\n\t\t\t\t$result = \"OOOPS \" + Str($Amount)\n\t\t\t}\n\t\t  }\n\t\t`}, `Conditions`: {`true`}, \"ApplicationId\": {\"1\"}}\n\tif err := postTx(`NewContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tform = url.Values{`Name`: {rnd + `Transfer`}, `Value`: {`{\"title\": \"Would you like to sign\",\n\t\t\"params\":[\n\t\t\t{\"name\": \"Receipient\", \"text\": \"Wallet\"},\n\t\t\t{\"name\": \"Amount\", \"text\": \"Amount(money)\"}\n\t\t\t]}`}, `Conditions`: {`true`}}\n\tif err := postTx(`NewSign`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr := postTx(rnd+`Test`, &url.Values{`Amount`: {`12345`}, `Recipient`: {`98765`}})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nvar (\n\timp = `{\n\t\t\"menus\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"test_%s\",\n\t\t\t\t\"Conditions\": \"ContractAccess(\\\"@1EditMenu\\\")\",\n\t\t\t\t\"Value\": \"MenuItem(main, Default Ecosystem Menu)\"\n\t\t\t}\n\t\t],\n\t\t\"contracts\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"testContract%[1]s\",\n\t\t\t\t\"Value\": \"contract testContract%[1]s {\\n    data {}\\n    conditions {}\\n    action {\\n        var res array\\n        res = DBFind(\\\"pages\\\").Columns(\\\"name\\\").Where({id: 1}).Order(\\\"id\\\")\\n        $result = res\\n    }\\n    }\",\n\t\t\t\t\"Conditions\": \"ContractConditions(` + \"`MainCondition`\" + `)\"\n\t\t\t}\n\t\t],\n\t\t\"pages\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"test_%[1]s\",\n\t\t\t\t\"Conditions\": \"ContractAccess(\\\"@1EditPage\\\")\",\n\t\t\t\t\"Menu\": \"default_menu\",\n\t\t\t\t\"Value\": \"P(class, Default Ecosystem Page)\\nImage().Style(width:100px;)\"\n\t\t\t}\n\t\t],\n\t\t\"blocks\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"test_%[1]s\",\n\t\t\t\t\"Conditions\": \"true\",\n\t\t\t\t\"Value\": \"block content\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Name\": \"test_a%[1]s\",\n\t\t\t\t\"Conditions\": \"true\",\n\t\t\t\t\"Value\": \"block content\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Name\": \"test_b%[1]s\",\n\t\t\t\t\"Conditions\": \"true\",\n\t\t\t\t\"Value\": \"block content\"\n\t\t\t}\n\t\t],\n\t\t\"tables\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"members%[1]s\",\n\t\t\t\t\"Columns\": \"[{\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"varchar\\\",\\\"conditions\\\":\\\"true\\\"},{\\\"name\\\":\\\"birthday\\\",\\\"type\\\":\\\"datetime\\\",\\\"conditions\\\":\\\"true\\\"},{\\\"name\\\":\\\"member_id\\\",\\\"type\\\":\\\"number\\\",\\\"conditions\\\":\\\"true\\\"},{\\\"name\\\":\\\"val\\\",\\\"type\\\":\\\"text\\\",\\\"conditions\\\":\\\"true\\\"},{\\\"name\\\":\\\"name_first\\\",\\\"type\\\":\\\"text\\\",\\\"conditions\\\":\\\"true\\\"},{\\\"name\\\":\\\"name_middle\\\",\\\"type\\\":\\\"text\\\",\\\"conditions\\\":\\\"true\\\"}]\",\n\t\t\t\t\"Permissions\": \"{\\\"insert\\\":\\\"true\\\",\\\"update\\\":\\\"true\\\",\\\"new_column\\\":\\\"true\\\"}\"\n\t\t\t}\n\t\t],\n\t\t\"parameters\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"host%[1]s\",\n\t\t\t\t\"Value\": \"\",\n\t\t\t\t\"Conditions\": \"ContractConditions(` + \"`MainCondition`\" + `)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Name\": \"host0%[1]s\",\n\t\t\t\t\"Value\": \"test\",\n\t\t\t\t\"Conditions\": \"ContractConditions(` + \"`MainCondition`\" + `)\"\n\t\t\t}\n\t\t],\n\t\t\"data\": [\n\t\t\t{\n\t\t\t\t\"Table\": \"members%[1]s\",\n\t\t\t\t\"Columns\": [\"name\",\"val\"],\n\t\t\t\t\"Data\": [\n\t\t\t\t\t[\"Bob\",\"Richard mark\"],\n\t\t\t\t\t[\"Mike Winter\",\"Alan summer\"]\n\t\t\t\t ]\n\t\t\t}\n\t\t]\n}`\n)\n\nfunc TestImport(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tname := crypto.RandSeq(4)\n\tform := url.Values{\"Data\": {fmt.Sprintf(imp, name)}}\n\terr := postTx(`@1Import`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n}\n\nfunc TestEditContracts_ChangeWallet(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(6)\n\tcode := `contract ` + rnd + ` {\n\t\tdata {\n\t\t\tPar string \"optional\"\n\t\t}\n\t\taction { $result = $par}}`\n\tform := url.Values{`Value`: {code}, `Conditions`: {`true`}}\n\tif err := postTx(`NewContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tvar ret getContractResult\n\terr := sendGet(`contract/`+rnd, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tkeyID := ret.WalletID\n\tsid := ret.TableID\n\tvar row rowResult\n\terr = sendGet(`row/contracts/`+sid, nil, &row)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif err := postTx(`ActivateContract`, &url.Values{`Id`: {sid}}); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tcode = row.Value[`value`]\n\tform = url.Values{`Id`: {sid}, `Value`: {code}, `Conditions`: {row.Value[`conditions`]}, `WalletId`: {\"1248-5499-7861-4204-5166\"}}\n\terr = postTx(`EditContract`, &form)\n\tif err == nil {\n\t\tt.Error(\"Expected `Contract activated` error\")\n\t\treturn\n\t}\n\terr = sendGet(`contract/`+rnd, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif ret.WalletID != keyID {\n\t\tt.Error(`wrong walletID`, ret.WalletID, keyID)\n\t\treturn\n\t}\n\tif err := postTx(`DeactivateContract`, &url.Values{`Id`: {sid}}); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif err := postTx(`EditContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = sendGet(`contract/`+rnd, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif ret.Address != \"1248-5499-7861-4204-5166\" {\n\t\tt.Error(`wrong address`, ret.Address, \"!= 1248-5499-7861-4204-5166\")\n\t\treturn\n\t}\n}\n\nfunc TestUpdateFunc(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `rnd` + crypto.RandSeq(6)\n\tform := url.Values{`Value`: {`contract f` + rnd + ` {\n\t\tdata {\n\t\t\tpar string\n\t\t}\n\t\tfunc action {\n\t\t\t$result = Sprintf(\"X=%s %s %s\", $par, $original_contract, $this_contract)\n\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\t_, id, err := postTxResult(`NewContract`, &form)\n\tassert.NoError(t, err)\n\n\tform = url.Values{`Value`: {`\n\t\tcontract one` + rnd + ` {\n\t\t\taction {\n\t\t\t\tvar ret map\n\t\t\t\tret = DBFind(\"contracts\").Columns(\"id,value\").WhereId(10).Row()\n\t\t\t\t$result = ret[\"id\"]\n\t\t}}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{`Value`: {`contract row` + rnd + ` {\n\t\t\t\taction {\n\t\t\t\t\tvar ret string\n\t\t\t\t\tret = DBFind(\"contracts\").Columns(\"id,value\").WhereId(11).One(\"id\")\n\t\t\t\t\t$result = ret\n\t\t\t\t}}\n\t\t\n\t\t\t`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\t_, msg, err := postTxResult(`one`+rnd, &url.Values{})\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"10\", msg)\n\n\t_, msg, err = postTxResult(`row`+rnd, &url.Values{})\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"11\", msg)\n\n\tform = url.Values{`Value`: {`\n\t\tcontract ` + rnd + ` {\n\t\t    data {\n\t\t\t\tPar string\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = f` + rnd + `(\"par\",$Par) + \" \" + $this_contract\n\t\t\t}}\n\t\t`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\t_, idcnt, err := postTxResult(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\t_, msg, err = postTxResult(rnd, &url.Values{`Par`: {`my param`}})\n\tassert.NoError(t, err)\n\tassert.Equal(t, fmt.Sprintf(`X=my param %s f%[1]s %[1]s`, rnd), msg)\n\n\tform = url.Values{`Id`: {id}, `Value`: {`\n\t\tfunc MyTest2(input string) string {\n\t\t\treturn \"Y=\"+input\n\t\t}`}, `Conditions`: {`true`}}\n\terr = postTx(`EditContract`, &form)\n\tassert.EqualError(t, postTx(`EditContract`, &form), `{\"type\":\"panic\",\"error\":\"Contracts or functions names cannot be changed\"}`)\n\n\tform = url.Values{`Id`: {id}, `Value`: {`contract f` + rnd + `{\n\t\tdata {\n\t\t\tpar string\n\t\t}\n\t\taction {\n\t\t\t$result = \"Y=\"+$par\n\t\t}}`}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`EditContract`, &form))\n\n\t_, msg, err = postTxResult(rnd, &url.Values{`Par`: {`new param`}})\n\tassert.NoError(t, err)\n\tassert.Equal(t, `Y=new param `+rnd, msg)\n\n\tform = url.Values{`Id`: {idcnt}, `Value`: {`\n\t\tcontract ` + rnd + ` {\n\t\t    data {\n\t\t\t\tPar string\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = f` + rnd + `(\"par\",$Par) + f` + rnd + `(\"par\",\"OK\")\n\t\t\t}}\n\t\t`}, `Conditions`: {`true`}}\n\t_, idcnt, err = postTxResult(`EditContract`, &form)\n\tassert.NoError(t, err)\n\n\t_, msg, err = postTxResult(rnd, &url.Values{`Par`: {`finish`}})\n\tassert.NoError(t, err)\n\tassert.Equal(t, `Y=finishY=OK`, msg)\n}\n\nfunc TestGlobalVars(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(4)\n\n\tform := url.Values{`Value`: {`\n\t\tcontract ` + rnd + ` {\n\t\t    data {\n\t\t\t\tPar string\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$Par = $Par + \"end\"\n\t\t\t\t$key_id = 1234\n\t\t\t\t$result = Str($key_id) + $Par\n\t\t\t}}\n\t\t`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\terr := postTx(`NewContract`, &form)\n\tif err == nil {\n\t\tt.Errorf(`must be error`)\n\t\treturn\n\t} else if err.Error() != `{\"type\":\"panic\",\"error\":\"system variable $key_id cannot be changed\"}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract c_` + rnd + ` {\n\t\tdata { Test string }\n\t\taction {\n\t\t\t$result = $Test + Str($ecosystem_id)\n\t\t}\n\t}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tform = url.Values{`Value`: {`\n\t\tcontract a_` + rnd + ` {\n\t\t\tdata { Par string}\n\t\t\tconditions {}\n\t\t\taction {\n\t\t\t\tvar params map\n\t\t\t\tparams[\"Test\"] = \"TEST\"\n\t\t\t\t$aaa = 123\n\t\t\t\tif $Par == \"b\" {\n\t\t\t\t    $result = CallContract(\"b_` + rnd + `\", params)\n\t\t\t\t} else {\n\t\t\t\t    $result = CallContract(\"c_` + rnd + `\", params) + c_` + rnd + `(\"Test\",\"OK\")\n\t\t\t\t}\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract b_` + rnd + ` {\n\t\t\tdata { Test string }\n\t\t\taction {\n\t\t\t\t$result = $Test + $aaa\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\terr = postTx(`a_`+rnd, &url.Values{\"Par\": {\"b\"}})\n\tif err == nil {\n\t\tt.Errorf(`must be error aaa`)\n\t\treturn\n\t} else if err.Error() != `{\"type\":\"panic\",\"error\":\"unknown extend identifier aaa\"}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\t_, msg, err := postTxResult(`a_`+rnd, &url.Values{\"Par\": {\"c\"}})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif msg != `TEST1OK1` {\n\t\tt.Errorf(`wrong result %s`, msg)\n\t\treturn\n\t}\n}\n\nfunc TestContractChain(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(4)\n\n\tform := url.Values{\"Name\": {rnd}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"value\",\"type\":\"varchar\", \"index\": \"0\", \n\t  \"conditions\":\"true\"},\n\t{\"name\":\"amount\", \"type\":\"number\",\"index\": \"0\", \"conditions\":\"true\"},\n\t{\"name\":\"dt\",\"type\":\"datetime\", \"index\": \"0\", \"conditions\":\"true\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\terr := postTx(`NewTable`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract sub` + rnd + ` {\n\t\tdata {\n\t\t\tId int\n\t\t}\n\t\taction {\n\t\t\t$row = DBFind(\"` + rnd + `\").Columns(\"value\").WhereId($Id)\n\t\t\tif Len($row) != 1 {\n\t\t\t\terror \"sub contract getting error\"\n\t\t\t}\n\t\t\t$record = $row[0]\n\t\t\t$new = $record[\"value\"]\n\t\t\tvar val string\n\t\t\tval = $new+\"=\"+$new\n\t\t\tDBUpdate(\"` + rnd + `\", $Id, {\"value\": val })\n\t\t}\n\t}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tform = url.Values{`Value`: {`contract ` + rnd + ` {\n\t\tdata {\n\t\t\tInitial string\n\t\t}\n\t\taction {\n\t\t\t$id = DBInsert(\"` + rnd + `\", {value: $Initial, amount:\"0\"})\n\t\t\tsub` + rnd + `($id)\n\t\t\t$row = DBFind(\"` + rnd + `\").Columns(\"value\").WhereId($id)\n\t\t\tif Len($row) != 1 {\n\t\t\t\terror \"contract getting error\"\n\t\t\t}\n\t\t\t$record = $row[0]\n\t\t\t$result = $record[\"value\"]\n\t\t}\n\t}\n\t\t`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\t_, msg, err := postTxResult(rnd, &url.Values{`Initial`: {rnd}})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif msg != rnd+`=`+rnd {\n\t\tt.Error(fmt.Errorf(`wrong result %s`, msg))\n\t}\n\n\tform = url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\taction {\n\t\t\tDBInsert(\"` + rnd + `\", {amount: 0,dt: \"timestamp NOW()\"})\n\t\t}\n\t}\n\t\t`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(rnd+`1`, &url.Values{}),\n\t\t`{\"type\":\"panic\",\"error\":\"It is prohibited to use Now() function\"}`)\n}\n\nfunc TestLoopCond(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(4)\n\n\tform := url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\tconditions {\n\t    \n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\terr := postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract ` + rnd + `2 {\n\t\t\t\tconditions {\n\t\t\t\t\tContractConditions(\"` + rnd + `1\")\n\t\t\t\t}\n\t\t\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret getContractResult\n\terr = sendGet(`contract/`+rnd+`1`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tsid := ret.TableID\n\tform = url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\t\t\tconditions {\n\t\t\t\t\tContractConditions(\"` + rnd + `2\")\n\t\t\t\t}\n\t\t\t}`}, `Id`: {sid}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\terr = postTx(`EditContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tassert.EqualError(t, postTx(rnd+`2`, &url.Values{}), `{\"type\":\"panic\",\"error\":\"There is loop in `+rnd+`1 contract\"}`)\n\n\tform = url.Values{\"Name\": {`ecosystems`}, \"InsertPerm\": {`ContractConditions(\"MainCondition\")`},\n\t\t\"UpdatePerm\":    {`EditEcosysName(1, \"HANG\")`},\n\t\t\"NewColumnPerm\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`EditTable`, &form))\n\tassert.EqualError(t, postTx(`EditEcosystemName`, &url.Values{\"EcosystemID\": {`1`},\n\t\t\"NewName\": {`Hang`}}), `{\"type\":\"panic\",\"error\":\"There is loop in EditEcosysName contract\"}`)\n\n\tform = url.Values{`Value`: {`contract ` + rnd + `shutdown {\n\t\taction\n\t\t{ DBInsert(\"` + rnd + `table\", {\"test\": \"SHUTDOWN\"}) }\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{\n\t\t\"Name\":          {rnd + `table`},\n\t\t\"Columns\":       {`[{\"name\":\"test\",\"type\":\"varchar\", \"index\": \"0\", \"conditions\":\"true\"}]`},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Permissions\":   {`{\"insert\": \"` + rnd + `shutdown()\", \"update\" : \"true\", \"new_column\": \"true\"}`},\n\t}\n\trequire.NoError(t, postTx(\"NewTable\", &form))\n\n\tassert.EqualError(t, postTx(rnd+`shutdown`, &url.Values{}), `{\"type\":\"panic\",\"error\":\"There is loop in @1`+rnd+`shutdown contract\"}`)\n}\n\nfunc TestRand(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(4)\n\n\tform := url.Values{`Value`: {`contract ` + rnd + ` {\n\t\taction {\n\t\t\tvar result i int\n\t\t\ti = 3\n\t\t\twhile i < 15 {\n\t\t\t\tvar rnd int\n\t\t\t\trnd = Random(0, 3*i)\n\t\t\t\tresult = result + rnd\n\t\t\t\ti=i+1\n\t\t\t}\n\t\t\t$result = result\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\t_, val1, err := postTxResult(rnd, &url.Values{})\n\tassert.NoError(t, err)\n\t_, val2, err := postTxResult(rnd, &url.Values{})\n\tassert.NoError(t, err)\n\t// val1 == val2 for seed = blockId % 1\n\tif val1 != val2 {\n\t\tt.Errorf(`%s!=%s`, val1, val2)\n\t}\n}\nfunc TestKillNode(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\tform := url.Values{\"Name\": {`MyTestContract1`}, \"Value\": {`contract MyTestContract1 {action {}}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}, \"nowait\": {`true`}}\n\trequire.NoError(t, postTx(`NewContract`, &form))\n\trequire.NoError(t, postTx(\"Kill\", &url.Values{\"nowait\": {`true`}}))\n}\n\nfunc TestLoopCondExt(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := `rnd` + crypto.RandSeq(4)\n\n\tform := url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\tconditions {\n\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\terr := postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract ` + rnd + `2 {\n\t\tconditions {\n\t\t\tContractConditions(\"` + rnd + `1\")\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\terr = postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret getContractResult\n\terr = sendGet(`contract/`+rnd+`1`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tsid := ret.TableID\n\tform = url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\tconditions {\n\t\t\tContractConditions(\"` + rnd + `2\")\n\t\t}\n\t}`}, `Id`: {sid}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\terr = postTx(`EditContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = postTx(rnd+`2`, &url.Values{})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestBlockTransactions(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\n\trnd := `rnd` + crypto.RandSeq(4)\n\n\tform := url.Values{`Value`: {`contract ` + rnd + `1 {\n\t\tconditions {\n\t    \n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\n\trequire.NoError(t, postTx(`NewContract`, &form))\n\n\tvar ret getContractResult\n\trequire.NoError(t, sendGet(`contract/`+rnd+`1`, nil, &ret))\n\n\tvar result map[int64][]TxInfo\n\trequire.NoError(t, sendGet(`blocks?block_id=1&count=10`, nil, &result))\n\n\tfmt.Printf(\"%+v\", result)\n}\n\nfunc TestCost(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`cnt`)\n\n\tform := url.Values{`Value`: {`contract ` + name + `1 {\n\t\tfunc my() {\n\t\t\tvar i int\n\t\t\twhile i < 1000 {\n\t\t\t\ti = i + 1\n\t\t\t}\n\t\t}\n\t\tconditions {\n\t\t\tvar i int\n\t\t\twhile i < 1000 {\n\t\t\t\ti = i + 1\n\t\t\t}\n\t\t}\n\t\taction {\n\t\t\tvar i int\n\t\t\twhile i < 10000 {\n\t\t\t\ti = i + 1\n\t\t\t}\n\t\t\tmy()\n\t\t\t$result = \"OK\"\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\n\trequire.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{`Value`: {`contract ` + name + `2 {\n\t\tconditions {\n\t\t\tvar i int\n\t\t\twhile i < 1000 {\n\t\t\t\ti = i + 1\n\t\t\t}\n\t\t}\n\t\taction {\n\t\t\tvar i int\n\t\t\twhile i < 10000 {\n\t\t\t\ti = i + 1\n\t\t\t}\n\t\t\t` + name + `1()\n\t\t\t$result = \"OK\"\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\n\trequire.NoError(t, postTx(`NewContract`, &form))\n\n\trequire.NoError(t, postTx(name+`1`, &url.Values{}))\n\trequire.NoError(t, postTx(name+`2`, &url.Values{}))\n\tt.Error(`OK`)\n\n}\n\nfunc TestHard(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\tname := randName(`h`)\n\tform := url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\tdata {\n\t\t\tPar int\n\t\t}\n\t\taction {}}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\t_, msg, err := postTxResult(`NewContract`, &form)\n\trequire.NoError(t, err)\n\tfmt.Println(`MSg=`, msg, name)\n\n\tfor i := 0; i < 1000; i++ {\n\t\tform = url.Values{\"Id\": {msg}, \"Value\": {fmt.Sprintf(`contract %s {action { \n\t\t\tPrintln(\"OK %d\")\n\t\t}}`, name, i)}, \"Conditions\": {`true`}, \"nowait\": {`true`}, \"Par\": {fmt.Sprintf(\"%d\", i)}}\n\t\tif err = postTx( /*name */ `EditContract`, &form); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n\tt.Error(`OK`)\n}\n\nfunc TestInsert(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`cnt`)\n\n\tform := url.Values{`Value`: {`contract ` + name + `1 {\n\t\tconditions {\n\t\t}\n\t\taction {\n\t\t\tNewTable(\"Name,Columns,ApplicationId,Permissions\", \"` + name + `2\",\n\t\t\t\t\"[{\\\"name\\\":\\\"MyName\\\",\\\"type\\\":\\\"varchar\\\", \\\"index\\\": \\\"0\\\", \\\"conditions\\\":{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"true\\\"}}]\", 100,\n\t\t\t\t \"{\\\"insert\\\": \\\"true\\\", \\\"update\\\" : \\\"true\\\", \\\"new_column\\\": \\\"true\\\"}\")\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\trequire.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{`Value`: {`contract ` + name + `2 {\n\t\taction {\n\t\t\tDBInsert(\"` + name + `2\", {MyName: \"insert\"})\n\t\t}\n\t}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\trequire.NoError(t, postTx(`NewContract`, &form))\n\n\trequire.NoError(t, postTx(name+`1`, &url.Values{}))\n\trequire.NoError(t, postTx(name+`2`, &url.Values{}))\n\tt.Error(`OK`)\n}\n\nfunc TestErrors(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`cnt`)\n\n\tform := url.Values{`Value`: {`contract ` + name + `1 {\n\t\taction {\n\t\t\t// comment\n\t\t\t DBFind(\"qq\")\n\t\t}}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tassert.EqualError(t, postTx(name+`1`, &url.Values{}),\n\t\t`{\"type\":\"panic\",\"error\":\"pq: relation \\\"1_qq\\\" does not exist [DBSelect @1`+name+`1:4]\"}`)\n\n\tform = url.Values{`Value`: {`contract ` + name + `2 {\n\t\t\t\taction {\n\t\t\t\t\t// comment\n\t\t\t\t\tvar i int\n\t\t\t\t\ti = 1/0\n\t\t\t\t}}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(name+`2`, &url.Values{}),\n\t\t`{\"type\":\"panic\",\"error\":\"divided by zero [@1`+name+`2:5]\"}`)\n\n\tform = url.Values{`Value`: {`contract ` + name + `5 {\n\t\t\taction {\n\t\t\t\t// comment\n\t\t\t\tThrow(\"Problem\", \"throw message\")\n\t\t\t}}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(name+`5`, &url.Values{}),\n\t\t`{\"type\":\"panic\",\"error\":\"throw message [Throw @1`+name+`5:4]\"}`)\n\n\tform = url.Values{`Value`: {`contract ` + name + `4 {\n\t\t\taction {\n\t\t\t\t// comment\n\t\t\t\terror(\"error message\")\n\t\t\t}}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(name+`4`, &url.Values{}),\n\t\t`{\"type\":\"error\",\"error\":\"error message\"}`)\n\n\tform = url.Values{`Value`: {`contract ` + name + `3 {\n\t\t        data {\n\t\t\t\t\tPar int\n\t\t\t\t}\n\t\t\t\taction {\n\t\t\t\t\tif $Par == 1 {\n\t\t\t\t\t   ` + name + `1()\n\t\t\t\t\t}\n\t\t\t\t\tif $Par == 2 {\n\t\t\t\t\t\t` + name + `2()\n\t\t\t\t\t }\n\t\t\t\t }}`}, `Conditions`: {`true`}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.EqualError(t, postTx(name+`3`, &url.Values{`Par`: {`1`}}),\n\t\t`{\"type\":\"panic\",\"error\":\"pq: relation \\\"1_qq\\\" does not exist [DBSelect @1`+name+`1:4 @1`+name+`3:6]\"}`)\n\tassert.EqualError(t, postTx(name+`3`, &url.Values{`Par`: {`2`}}),\n\t\t`{\"type\":\"panic\",\"error\":\"divided by zero [@1`+name+`2:5 @1`+name+`3:9]\"}`)\n\n\tt.Error(`OK`)\n}\n\nfunc TestExternalNetwork(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tvar form url.Values\n\tname := `cnt` + crypto.RandSeq(4)\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `Hashes {\n\t\tdata {\n\t\t\thash string\n\t\t\tblock int\n\t\t\tUID    string\n\t\t}\n\t\taction { \n\t\t\tPrintln(\"SUCCESS\", $UID, $hash, $block )\n\t\t\tif $UID == \"123456\" {\n\t\t\t\t$result = \"ok\"\n\t\t\t}\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `Result {\n\t\tdata {\n\t\t\tUID  string\n\t\t\tStatus int\n\t\t\tBlock int\n\t\t\tMsg   string \"optional\"\n\t\t}\n\t\taction { \n\t\t\tPrintln(\"Result Contract\", $UID, $Status, $Block, $Msg )\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `Errors {\n\t\tdata {\n\t\t\thash string\n\t\t\tblock int\n\t\t\tUID    string \"optional\"\n\t\t}\n\t\taction { \n\t\t\tif $UID == \"stop\" {\n\t\t\t\terror(\"Error message\")\n\t\t\t}\n\t\t\t$result = 1/0\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `2 {\n\t\taction { \n\t\t\tvar params map\n\t\t\tparams[\"hash\"] = PubToHex($txhash)\n\t\t\tparams[\"block\"] = $block\n\t\t\tSendExternalTransaction( \"123456\", \"http://localhost:7079\", \"@1` + name + `Hashes\",   \n\t\t\t    params, \"@1` + name + `Result\")\n\t\t\tSendExternalTransaction( \"654321\", \"http://localhost:7079\", \"@1` + name + `Hashes\",  \n\t\t\t    params, \"@1` + name + `Result\")\n\t\t\tSendExternalTransaction( \"stop\", \"http://localhost:7079\", \"@1` + name + `Errors\", \n\t\t\t    params, \"@1` + name + `Result\")\n\t\t\tSendExternalTransaction( \"zero\", \"http://localhost:7079\", \"@1` + name + `Errors\", \n\t\t\t    params, \"@1` + name + `Result\")\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.NoError(t, postTx(name+`2`, &url.Values{}))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `3 {\n\t\taction { \n\t\t\tvar params map\n\t\t\tparams[\"hash\"] = PubToHex($txhash)\n\t\t\tparams[\"block\"] = $block\n\t\t\tSendExternalTransaction( \"77\", \"http://localhost:7079\", \"@1` + name + `Hashes\",   \n\t\t\t    params, \"@1None\")\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.NoError(t, postTx(name+`3`, &url.Values{}))\n}\n\nfunc TestApos(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tname := randName(`cnt`)\n\tform := url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\tdata {\n\t\t\tAddress string\n\t\t}\n\t\taction {\n\t\t\tvar m map\n\t\t\tvar id int\n\t\t\tm[\"member_name\"] = \"test\"\n\t\t\tm[\"member_info->country\"] = $Address \n\t\t\tm[\"member_info->ooops\"] = \"seses' seseses \"\n\t\t\tid = DBInsert(\"members\", m)\n\t\t\tm[\"member_info->new\"] = \"ok'; ok\"\n\t\t\tm[\"memb'er_info->ne'wq\"] = \"stop'\"\n\t\t\tDBUpdate(\"members\", id, m)\n\t\t}}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tassert.NoError(t, postTx(name, &url.Values{`Address`: {\"Name d'Company\"}}))\n}\n\nfunc TestCondition(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tvar form url.Values\n\n\tname := `cnt` + crypto.RandSeq(4)\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\taction { \n\t\t\tPrintln(\"COND\" )\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\tform = url.Values{\"Name\": {name + `2`}, \"Value\": {`contract ` + name + `2 {\n\t\tconditions {\n\t\t}\n\t\taction { \n\t\t\tPrintln(\"COND 2\" )\n\t\t}\n\t}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tassert.NoError(t, postTx(`NewPage`, &url.Values{\n\t\t\"ApplicationId\": {`1`},\n\t\t\"Name\":          {name},\n\t\t\"Value\":         {`Div(Body: \"Condition 2 - test\")`},\n\t\t\"Menu\":          {`default_menu`},\n\t\t\"Conditions\":    {`ContractConditions(\"` + name + `2\")`},\n\t}))\n\tvar ret listResult\n\terr := sendGet(`list/pages`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tid := strconv.FormatInt(ret.Count, 10)\n\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\n\t\t\"Id\":         {id},\n\t\t\"Value\":      {`Div(Body: \"Condition 1 - test\")`},\n\t\t\"Conditions\": {`ContractConditions(\"` + name + `\")`},\n\t}))\n\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\n\t\t\"Id\":         {id},\n\t\t\"Value\":      {`Div(Body: \"Condition - test\")`},\n\t\t\"Conditions\": {`true`},\n\t}))\n}\n\nfunc TestCurrentKeyFromAccount(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tname := randName(t.Name())\n\tform := url.Values{\n\t\t\"Name\": {name},\n\t\t\"Value\": {`contract ` + name + ` {\n\t\t\tdata {\n\t\t\t\tAccount string\n\t\t\t}\n\t\t\taction {\n\t\t\t\tinfo CurrentKeyFromAccount($Account)\n\t\t\t}\n\t\t}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Conditions\":    {\"true\"},\n\t}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\texpected := fmt.Sprintf(`{\"type\":\"info\",\"error\":\"%d\"}`, converter.StringToAddress(gAddress))\n\tassert.Error(t, postTx(name, &url.Values{`Account`: {gAddress}}), expected)\n}\n"
  },
  {
    "path": "packages/api/contracts.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype contractsResult struct {\n\tCount string              `json:\"count\"`\n\tList  []map[string]string `json:\"list\"`\n}\n\nfunc getContractsHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &paginatorForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tcontract := &sqldb.Contract{}\n\tcontract.EcosystemID = client.EcosystemID\n\n\tcount, err := contract.CountByEcosystem()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting table records count\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tcontracts, err := contract.GetListByEcosystem(form.Offset, form.Limit)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tlist := make([]map[string]string, len(contracts))\n\tfor i, c := range contracts {\n\t\tlist[i] = c.ToMap()\n\t\tlist[i][\"address\"] = converter.AddressToString(c.WalletID)\n\t}\n\n\tif len(list) == 0 {\n\t\tlist = nil\n\t}\n\n\tjsonResponse(w, &listResult{\n\t\tCount: count,\n\t\tList:  list,\n\t})\n}\n"
  },
  {
    "path": "packages/api/data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst binaryColumn = \"data\"\n\nfunc compareHash(data []byte, urlHash string) bool {\n\turlHash = strings.ToLower(urlHash)\n\n\tvar hash []byte\n\tswitch len(urlHash) {\n\tcase 32:\n\t\th := md5.Sum(data)\n\t\thash = h[:]\n\tcase 64:\n\t\thash = crypto.Hash(data)\n\t}\n\n\treturn hex.EncodeToString(hash) == urlHash\n}\n\nfunc getDataHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\ttable, column := params[\"table\"], params[\"column\"]\n\n\tid, err := strconv.ParseInt(params[\"id\"], 10, 64)\n\tif err != nil {\n\t\terrorResponse(w, errParamNotFound.Errorf(\"id\"))\n\t\treturn\n\t}\n\tdata, err := sqldb.GetColumnByID(table, column, id)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting data from table\")\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tif !compareHash([]byte(data), params[\"hash\"]) {\n\t\terrorResponse(w, errHashWrong)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"application/octet-stream\")\n\tw.Header().Set(\"Content-Disposition\", \"attachment\")\n\tw.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\n\tw.Write([]byte(data))\n\treturn\n}\n\nfunc getBinaryHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\tbin := sqldb.Binary{}\n\tfound, err := bin.GetByID(converter.StrToInt64(params[\"id\"]))\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Errorf(\"getting binary by id\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif !found {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tif !compareHash(bin.Data, params[\"hash\"]) {\n\t\terrorResponse(w, errHashWrong)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", bin.MimeType)\n\tw.Header().Set(\"Content-Disposition\", fmt.Sprintf(`attachment; filename=\"%s\"`, bin.Name))\n\tw.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\n\tw.Write(bin.Data)\n\treturn\n}\n"
  },
  {
    "path": "packages/api/ecosystem.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc getEcosystemNameHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\n\tecosystemID := converter.StrToInt64(r.FormValue(\"id\"))\n\tecosystems := sqldb.Ecosystem{}\n\tfound, err := ecosystems.Get(nil, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting ecosystem name\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"ecosystem_id\": ecosystemID}).Debug(\"ecosystem by id not found\")\n\t\terrorResponse(w, errParamNotFound.Errorf(\"name\"))\n\t\treturn\n\t}\n\n\tjsonResponse(w, &struct {\n\t\tEcosystemName string `json:\"ecosystem_name\"`\n\t}{\n\t\tEcosystemName: ecosystems.Name,\n\t})\n}\n"
  },
  {
    "path": "packages/api/ecosystem_params.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype paramResult struct {\n\tID         string `json:\"id\"`\n\tName       string `json:\"name\"`\n\tValue      string `json:\"value\"`\n\tConditions string `json:\"conditions\"`\n}\n\ntype paramsResult struct {\n\tList []paramResult `json:\"list\"`\n}\n\nfunc (m Mode) getEcosystemParamsHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &appParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: m.EcosystemGetter,\n\t\t},\n\t}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tlogger := getLogger(r)\n\n\tsp := &sqldb.StateParameter{}\n\tsp.SetTablePrefix(form.EcosystemPrefix)\n\tnames := strings.Split(form.Names, \",\")\n\tlist, err := sp.GetAllStateParameters(nil, nil, names)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting all state parameters\")\n\t}\n\n\tresult := &paramsResult{\n\t\tList: make([]paramResult, 0),\n\t}\n\n\tfor _, item := range list {\n\t\tresult.List = append(result.List, paramResult{\n\t\t\tID:         converter.Int64ToStr(item.ID),\n\t\t\tName:       item.Name,\n\t\t\tValue:      item.Value,\n\t\t\tConditions: item.Conditions,\n\t\t})\n\t}\n\n\tjsonResponse(w, result)\n}\n\nfunc (m Mode) getEcosystemParamHandler(w http.ResponseWriter, r *http.Request) {\n\tlogger := getLogger(r)\n\n\tform := &ecosystemForm{\n\t\tValidator: m.EcosystemGetter,\n\t}\n\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\n\tsp := &sqldb.StateParameter{}\n\tsp.SetTablePrefix(form.EcosystemPrefix)\n\tname := params[\"name\"]\n\n\tif found, err := sp.Get(nil, name); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting state parameter by name\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t} else if !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"key\": name}).Debug(\"state parameter not found\")\n\t\terrorResponse(w, errParamNotFound.Errorf(name))\n\t\treturn\n\t}\n\n\tjsonResponse(w, &paramResult{\n\t\tID:         converter.Int64ToStr(sp.ID),\n\t\tName:       sp.Name,\n\t\tValue:      sp.Value,\n\t\tConditions: sp.Conditions,\n\t})\n}\n"
  },
  {
    "path": "packages/api/ecosystem_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewEcosystem(t *testing.T) {\n\tvar (\n\t\terr error\n\t)\n\tif err = keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform := url.Values{`Name`: {`test`}}\n\tif _, _, err = postTxResult(`NewEcosystem`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Name`: {crypto.RandSeq(13)}}\n\tif err := postTx(`NewEcosystem`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestEditEcosystem(t *testing.T) {\n\tvar (\n\t\terr error\n\t)\n\tif err = keyLogin(2); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tmenu := `government`\n\tvalue := `P(test,test paragraph)`\n\n\tname := randName(`page`)\n\tform := url.Values{\"Name\": {name}, \"Value\": {value},\n\t\t\"Menu\": {menu}, \"Conditions\": {\"ContractConditions(`MainCondition`)\"}}\n\terr = postTx(`@1NewPage`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = postTx(`@1NewPage`, &form)\n\tif cutErr(err) != fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Page %s already exists\"}`, name) {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{\"Name\": {name}, \"Value\": {`MenuItem(default_page)`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {\"ContractConditions(`MainCondition`)\"}}\n\tassert.NoError(t, postTx(`@1NewMenu`, &form))\n\n\tform = url.Values{\"Id\": {`1`}, \"Value\": {value},\n\t\t\"Menu\": {menu}, \"Conditions\": {\"ContractConditions(`MainCondition`)\"}}\n\terr = postTx(`@1EditPage`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tnameCont := randName(`test`)\n\tform = url.Values{\"Value\": {`contract ` + nameCont + ` {\n\t\taction { Test(\"empty\",  \"empty value\")}}`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\t_, id, err := postTxResult(`@1NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{\"Id\": {id}, \"Value\": {`contract ` + nameCont + ` {\n\t\taction { Test(\"empty3\",  \"empty value\")}}`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tif err := postTx(`@1EditContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tgAuth = ``\n\tif err = keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret contentResult\n\tassert.NoError(t, sendPost(`content/page/@2`+name, &url.Values{}, &ret))\n\tif RawToString(ret.Tree) != `[{\"tag\":\"p\",\"attr\":{\"class\":\"test paragraph\"},\"children\":[{\"tag\":\"text\",\"text\":\"test\"}]}]` {\n\t\tt.Errorf(`%s != %s`, RawToString(ret.Tree), `[{\"tag\":\"p\",\"attr\":{\"class\":\"test paragraph\"},\"children\":[{\"tag\":\"text\",\"text\":\"test\"}]}]`)\n\t}\n\tassert.NoError(t, sendPost(`content/menu/@2`+name, &url.Values{}, &ret))\n\tif RawToString(ret.Tree) != `[{\"tag\":\"menuitem\",\"attr\":{\"title\":\"default_page\"}}]` {\n\t\tt.Errorf(`%s != %s`, RawToString(ret.Tree), `[{\"tag\":\"menuitem\",\"attr\":{\"title\":\"default_page\"}}]`)\n\t}\n}\n\nfunc TestPlatformParams(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\n\tvar ret paramsResult\n\trequire.NoError(t, sendGet(`ecosystemparams`, nil, &ret))\n\n\tif len(ret.List) < 5 {\n\t\tt.Error(fmt.Errorf(`wrong count of parameters %d`, len(ret.List)))\n\t}\n\n\trequire.NoError(t, sendGet(`ecosystemparams?names=ecosystem_name,new_table&ecosystem=1`, nil, &ret))\n\n\trequire.Equalf(t, 1, len(ret.List), `wrong count of parameters %d`, len(ret.List))\n}\n\nfunc TestSystemParams(t *testing.T) {\n\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tvar ret paramsResult\n\n\terr := sendGet(`systemparams`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tassert.Equal(t, 66, len(ret.List), `wrong count of parameters %d`, len(ret.List))\n}\n\nfunc TestSomeSystemParam(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tvar ret paramsResult\n\n\tparam := \"gap_between_blocks\"\n\terr := sendGet(`systemparams/?names=`+param, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tassert.Equal(t, 1, len(ret.List), \"parameter %s not found\", param)\n}\n\nfunc TestEcosystemParam(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret, ret1 paramResult\n\terr := sendGet(`ecosystemparam/changing_menu`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif ret.Value != `ContractConditions(\"MainCondition\")` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = sendGet(`ecosystemparam/myval`, nil, &ret1)\n\tif err != nil && err.Error() != `400 {\"error\": \"E_PARAMNOTFOUND\", \"msg\": \"Parameter myval has not been found\" , \"params\": [\"myval\"]}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret1.Value) != 0 {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestAppParams(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := `rnd` + crypto.RandSeq(3)\n\tform := url.Values{`ApplicationId`: {`1`}, `Name`: {rnd + `1`}, `Value`: {`simple string,index`}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewAppParam`, &form))\n\n\tform[`Name`] = []string{rnd + `2`}\n\tform[`Value`] = []string{`another string`}\n\tassert.NoError(t, postTx(`NewAppParam`, &form))\n\n\tvar ret appParamsResult\n\tassert.NoError(t, sendGet(`appparams/1`, nil, &ret))\n\tif len(ret.List) < 2 {\n\t\tt.Error(fmt.Errorf(`wrong count of parameters %d`, len(ret.List)))\n\t\treturn\n\t}\n\n\tassert.NoError(t, sendGet(fmt.Sprintf(`appparams/1?names=%s1,%[1]s2&ecosystem=1`, rnd), nil, &ret))\n\tassert.Len(t, ret.List, 2)\n\n\tvar ret1, ret2 paramResult\n\tassert.NoError(t, sendGet(`appparam/1/`+rnd+`2`, nil, &ret1))\n\tassert.Equal(t, `another string`, ret1.Value)\n\n\tform[`Id`] = []string{ret1.ID}\n\tform[`Name`] = []string{rnd + `2`}\n\tform[`Value`] = []string{`{\"par1\":\"value 1\", \"par2\":\"value 2\"}`}\n\tassert.NoError(t, postTx(`EditAppParam`, &form))\n\n\tform = url.Values{\"Value\": {`contract ` + rnd + `Par { data {} conditions {} action\n\t{ var row map\n\t\trow=JSONDecode(AppParam(1, \"` + rnd + `2\", 1))\n\t    $result = row[\"par1\"] }\n\t}`}, \"Conditions\": {\"true\"}, `ApplicationId`: {`1`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\t_, msg, err := postTxResult(rnd+`Par`, &form)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"value 1\", msg)\n\n\tforTest := tplList{{`AppParam(` + rnd + `1, 1, Source: myname)`,\n\t\t`[{\"tag\":\"data\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"1\",\"simple string\"],[\"2\",\"index\"]],\"source\":\"myname\",\"types\":[\"text\",\"text\"]}}]`},\n\t\t{`SetVar(myapp, 1)AppParam(` + rnd + `2, App: #myapp#)`,\n\t\t\t`[{\"tag\":\"text\",\"text\":\"{\"par1\":\"value 1\", \"par2\":\"value 2\"}\"}]`}}\n\tfor _, item := range forTest {\n\t\tvar ret contentResult\n\t\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {item.input}}, &ret))\n\t\tassert.Equal(t, item.want, RawToString(ret.Tree))\n\t}\n\n\tassert.EqualError(t, sendGet(`appparam/1/myval`, nil, &ret2), `404 {\"error\":\"E_PARAMNOTFOUND\",\"msg\":\"Parameter myval has not been found\"}`)\n\tassert.Len(t, ret2.Value, 0)\n}\n"
  },
  {
    "path": "packages/api/errors.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n)\n\nvar (\n\tdefaultStatus        = http.StatusBadRequest\n\tErrEcosystemNotFound = errors.New(\"Ecosystem not found\")\n\terrContract          = errType{\"E_CONTRACT\", \"There is not %s contract\", http.StatusNotFound}\n\terrDBNil             = errType{\"E_DBNIL\", \"DB is nil\", defaultStatus}\n\terrDeletedKey        = errType{\"E_DELETEDKEY\", \"The key is deleted\", http.StatusForbidden}\n\terrEcosystem         = errType{\"E_ECOSYSTEM\", \"Ecosystem %d doesn't exist\", defaultStatus}\n\terrEmptyPublic       = errType{\"E_EMPTYPUBLIC\", \"Public key is undefined\", http.StatusBadRequest}\n\terrKeyNotFound       = errType{\"E_KEYNOTFOUND\", \"Key has not been found\", http.StatusNotFound}\n\terrEmptySign         = errType{\"E_EMPTYSIGN\", \"Signature is undefined\", defaultStatus}\n\terrHashWrong         = errType{\"E_HASHWRONG\", \"Hash is incorrect\", http.StatusBadRequest}\n\terrHashNotFound      = errType{\"E_HASHNOTFOUND\", \"Hash %s has not been found\", defaultStatus}\n\terrHeavyPage         = errType{\"E_HEAVYPAGE\", \"This page is heavy\", defaultStatus}\n\terrInstalled         = errType{\"E_INSTALLED\", \"Chain is already installed\", defaultStatus}\n\terrInvalidWallet     = errType{\"E_INVALIDWALLET\", \"Wallet %s is not valid\", http.StatusBadRequest}\n\terrLimitForsign      = errType{\"E_LIMITFORSIGN\", \"Length of forsign is too big (%d)\", defaultStatus}\n\terrLimitTxSize       = errType{\"E_LIMITTXSIZE\", \"The size of tx is too big (%d)\", defaultStatus}\n\terrNotFound          = errType{\"E_NOTFOUND\", \"Page not found\", http.StatusNotFound}\n\terrNotFoundRecord    = errType{\"E_NOTFOUND\", \"Record not found\", http.StatusNotFound}\n\terrParamNotFound     = errType{\"E_PARAMNOTFOUND\", \"Parameter %s has not been found\", http.StatusNotFound}\n\terrPermission        = errType{\"E_PERMISSION\", \"Permission denied\", http.StatusUnauthorized}\n\terrQuery             = errType{\"E_QUERY\", \"DB query is wrong\", http.StatusInternalServerError}\n\terrRecovered         = errType{\"E_RECOVERED\", \"API recovered\", http.StatusInternalServerError}\n\terrServer            = errType{\"E_SERVER\", \"Server error\", defaultStatus}\n\terrSignature         = errType{\"E_SIGNATURE\", \"Signature is incorrect\", http.StatusBadRequest}\n\terrUnknownSign       = errType{\"E_UNKNOWNSIGN\", \"Unknown signature\", defaultStatus}\n\terrStateLogin        = errType{\"E_STATELOGIN\", \"%d is not a membership of ecosystem %d\", http.StatusForbidden}\n\terrTableNotFound     = errType{\"E_TABLENOTFOUND\", \"Table %s has not been found\", http.StatusNotFound}\n\terrToken             = errType{\"E_TOKEN\", \"Token is not valid\", defaultStatus}\n\terrTokenExpired      = errType{\"E_TOKENEXPIRED\", \"Token is expired by %s\", http.StatusUnauthorized}\n\terrUnauthorized      = errType{\"E_UNAUTHORIZED\", \"Unauthorized\", http.StatusUnauthorized}\n\terrUndefineval       = errType{\"E_UNDEFINEVAL\", \"Value %s is undefined\", defaultStatus}\n\terrUnknownUID        = errType{\"E_UNKNOWNUID\", \"Unknown uid\", defaultStatus}\n\terrCLB               = errType{\"E_CLB\", \"Virtual Dedicated Ecosystem %d doesn't exist\", defaultStatus}\n\terrCLBCreated        = errType{\"E_CLBCREATED\", \"Virtual Dedicated Ecosystem is already created\", http.StatusBadRequest}\n\terrRequestNotFound   = errType{\"E_REQUESTNOTFOUND\", \"Request %s doesn't exist\", defaultStatus}\n\terrUpdating          = errType{\"E_UPDATING\", \"Node is updating blockchain, block height %d\", http.StatusServiceUnavailable}\n\terrStopping          = errType{\"E_STOPPING\", \"Network is stopping\", http.StatusServiceUnavailable}\n\terrNotImplemented    = errType{\"E_NOTIMPLEMENTED\", \"Not implemented\", http.StatusNotImplemented}\n\terrParamMoneyDigit   = errType{\"E_PARAMMONEYDIGIT\", \"The number of decimal places cannot be exceeded ( %s )\", http.StatusBadRequest}\n\terrDiffKey           = errType{\"E_DIFKEY\", \"Sender's key is different from tx key\", defaultStatus}\n\terrBanned            = errType{\"E_BANNED\", \"The key %d is banned till %s\", http.StatusForbidden}\n\terrCheckRole         = errType{\"E_CHECKROLE\", \"Access denied\", http.StatusForbidden}\n\terrNewUser           = errType{\"E_NEWUSER\", \"The block packing in progress, please wait\", http.StatusUnauthorized}\n\terrEcoNotOpen        = errType{\"E_ECONOTOPEN\", \"The ecosystem (%d) is not open and cannot be registered address\", http.StatusUnauthorized}\n)\n\ntype errType struct {\n\tErr     string `json:\"error\"`\n\tMessage string `json:\"msg\"`\n\tStatus  int    `json:\"-\"`\n}\n\nfunc (et errType) Error() string {\n\treturn et.Err\n}\n\nfunc (et errType) Errorf(v ...any) errType {\n\tet.Message = fmt.Sprintf(et.Message, v...)\n\treturn et\n}\n"
  },
  {
    "path": "packages/api/getcontract.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype contractField struct {\n\tName     string `json:\"name\"`\n\tType     string `json:\"type\"`\n\tOptional bool   `json:\"optional\"`\n}\n\ntype getContractResult struct {\n\tID         uint32          `json:\"id\"`\n\tStateID    uint32          `json:\"state\"`\n\tTableID    string          `json:\"tableid\"`\n\tWalletID   string          `json:\"walletid\"`\n\tTokenID    string          `json:\"tokenid\"`\n\tAddress    string          `json:\"address\"`\n\tFields     []contractField `json:\"fields\"`\n\tName       string          `json:\"name\"`\n\tAppId      uint32          `json:\"app_id\"`\n\tEcosystem  uint32          `json:\"ecosystem\"`\n\tConditions string          `json:\"conditions\"`\n}\n\nfunc getContractInfoHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\tcontract := getContract(r, params[\"name\"])\n\tif contract == nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ContractError, \"contract_name\": params[\"name\"]}).Debug(\"contract name\")\n\t\terrorResponse(w, errContract.Errorf(params[\"name\"]))\n\t\treturn\n\t}\n\n\tvar result getContractResult\n\tinfo := getContractInfo(contract)\n\tcon := &sqldb.Contract{}\n\texits, err := con.Get(info.Owner.TableID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"contract_id\": info.Owner.TableID}).Error(\"get contract\")\n\t\terrorResponse(w, errQuery)\n\t\treturn\n\t}\n\tif !exits {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ContractError, \"contract id\": info.Owner.TableID}).Debug(\"get contract\")\n\t\terrorResponse(w, errContract.Errorf(params[\"name\"]))\n\t\treturn\n\t}\n\tfields := make([]contractField, 0)\n\tresult = getContractResult{\n\t\tID:         uint32(info.Owner.TableID + consts.ShiftContractID),\n\t\tTableID:    converter.Int64ToStr(info.Owner.TableID),\n\t\tName:       info.Name,\n\t\tStateID:    info.Owner.StateID,\n\t\tWalletID:   converter.Int64ToStr(info.Owner.WalletID),\n\t\tTokenID:    converter.Int64ToStr(info.Owner.TokenID),\n\t\tAddress:    converter.AddressToString(info.Owner.WalletID),\n\t\tEcosystem:  uint32(con.EcosystemID),\n\t\tAppId:      uint32(con.AppID),\n\t\tConditions: con.Conditions,\n\t}\n\n\tif info.Tx != nil {\n\t\tfor _, fitem := range *info.Tx {\n\t\t\tfields = append(fields, contractField{\n\t\t\t\tName:     fitem.Name,\n\t\t\t\tType:     script.OriginalToString(fitem.Original),\n\t\t\t\tOptional: fitem.ContainsTag(script.TagOptional),\n\t\t\t})\n\t\t}\n\t}\n\tresult.Fields = fields\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/getuid.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"math/rand\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\t\"github.com/golang-jwt/jwt/v4\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst jwtUIDExpire = time.Second * 5\n\ntype getUIDResult struct {\n\tUID         string `json:\"uid,omitempty\"`\n\tToken       string `json:\"token,omitempty\"`\n\tExpire      string `json:\"expire,omitempty\"`\n\tEcosystemID string `json:\"ecosystem_id,omitempty\"`\n\tKeyID       string `json:\"key_id,omitempty\"`\n\tAddress     string `json:\"address,omitempty\"`\n\tNetworkID   string `json:\"network_id,omitempty\"`\n\tCryptoer    string `json:\"cryptoer\"`\n\tHasher      string `json:\"hasher\"`\n}\n\nfunc getUIDHandler(w http.ResponseWriter, r *http.Request) {\n\tresult := new(getUIDResult)\n\tresult.NetworkID = converter.Int64ToStr(conf.Config.LocalConf.NetworkID)\n\ttoken := getToken(r)\n\tresult.Cryptoer, result.Hasher = conf.Config.CryptoSettings.Cryptoer, conf.Config.CryptoSettings.Hasher\n\tif token != nil {\n\t\tif claims, ok := token.Claims.(*JWTClaims); ok && len(claims.KeyID) > 0 {\n\t\t\tresult.EcosystemID = claims.EcosystemID\n\t\t\tresult.Expire = claims.ExpiresAt.Sub(time.Now()).String()\n\t\t\tresult.KeyID = claims.KeyID\n\t\t\tresult.Address = converter.AddressToString(converter.StrToInt64(claims.KeyID))\n\t\t\tjsonResponse(w, result)\n\t\t\treturn\n\t\t}\n\t}\n\n\tresult.UID = converter.Int64ToStr(rand.New(rand.NewSource(time.Now().Unix())).Int63())\n\tclaims := JWTClaims{\n\t\tUID:         result.UID,\n\t\tEcosystemID: \"1\",\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\tExpiresAt: &jwt.NumericDate{Time: time.Now().Add(jwtUIDExpire)},\n\t\t},\n\t}\n\n\tvar err error\n\tif result.Token, err = generateJWTToken(claims); err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JWTError, \"error\": err}).Error(\"generating jwt token\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/getuid_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetUID(t *testing.T) {\n\tvar ret getUIDResult\n\terr := sendGet(`getuid`, nil, &ret)\n\tif err != nil {\n\t\tvar v map[string]string\n\t\tjson.Unmarshal([]byte(err.Error()[4:]), &v)\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tgAuth = ret.Token\n\tpriv, pub, err := crypto.GenHexKeys()\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tsign, err := crypto.SignString(priv, `LOGIN`+ret.NetworkID+ret.UID)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform := url.Values{\"pubkey\": {pub}, \"signature\": {hex.EncodeToString(sign)}}\n\tvar lret loginResult\n\terr = sendPost(`login`, &form, &lret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tgAuth = lret.Token\n}\n\nfunc TestNetwork(t *testing.T) {\n\tvar ret NetworkResult\n\tassert.NoError(t, sendGet(`network`, nil, &ret))\n\tif len(ret.NetworkID) == 0 || len(ret.CentrifugoURL) == 0 || len(ret.HonorNodes) == 0 {\n\t\tt.Error(`Wrong value`, ret)\n\t}\n}\n"
  },
  {
    "path": "packages/api/history.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst rollbackHistoryLimit = 100\n\ntype historyResult struct {\n\tList []map[string]string `json:\"list\"`\n}\n\nfunc getHistoryHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\n\ttable := client.Prefix() + \"_\" + params[\"name\"]\n\trollbackTx := &sqldb.RollbackTx{}\n\ttxs, err := rollbackTx.GetRollbackTxsByTableIDAndTableName(params[\"id\"], table, rollbackHistoryLimit)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"rollback history\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\trollbackList := []map[string]string{}\n\tfor _, tx := range *txs {\n\t\tif tx.Data == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\trollback := map[string]string{}\n\t\tif err := json.Unmarshal([]byte(tx.Data), &rollback); err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling rollbackTx.Data from JSON\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\trollbackList = append(rollbackList, rollback)\n\t}\n\n\tjsonResponse(w, &historyResult{rollbackList})\n}\n"
  },
  {
    "path": "packages/api/history_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\tstdErrors \"errors\"\n\t\"testing\"\n)\n\nfunc TestHistory(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tvar ret historyResult\n\terr := sendGet(\"history/pages/1\", nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret.List) == 0 {\n\t\tt.Error(stdErrors.New(\"History should not be empty\"))\n\t}\n\n\terr = sendGet(\"history/pages/1000\", nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret.List) != 0 {\n\t\tt.Error(stdErrors.New(\"History should be empty\"))\n\t}\n}\n"
  },
  {
    "path": "packages/api/import_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\nfunc ImportApps(path, appname string) error {\n\tapps, err := os.ReadFile(path + \"/\" + appname + \".json\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar val = make(map[any]any)\n\tval[\"Body\"] = apps\n\tval[\"MimeType\"] = \"application/json\"\n\tval[\"Name\"] = appname + \".json\"\n\n\tparams := contractParams{\n\t\t\"Data\": val,\n\t}\n\t_, _, err = postTxResult(\"ImportUpload\", &params)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Println(\"successful upload \", val[\"Name\"], \"---------------\")\n\tdamap, err := smart.JSONDecode(string(apps))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, o := damap.(*types.Map).Get(\"data\"); o {\n\t\tvals := converter.MarshalJson(damap.(*types.Map).Values()[1])\n\n\t\tparams2 := url.Values{`Data`: {vals}}\n\t\t_, _, err = postTxResult(\"Import\", &params2)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Println(\"successful import \", val[\"Name\"], \"---------------\")\n\t} else {\n\t\treturn errors.New(\"nil data\")\n\t}\n\treturn nil\n}\nfunc TestImportApps(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tpath, err := os.Getwd()\n\tassert.NoError(t, err)\n\tassert.NoError(t, ImportApps(path, \"system\"))\n\tassert.NoError(t, ImportApps(path, \"conditions\"))\n\tassert.NoError(t, ImportApps(path, \"basic\"))\n\tassert.NoError(t, ImportApps(path, \"lang_res\"))\n\tassert.NoError(t, ImportApps(path, \"platform_apps/ecosystems_catalog\"))\n\tassert.NoError(t, ImportApps(path, \"platform_apps/token_emission\"))\n\tform := url.Values{}\n\tassert.NoError(t, postTx(`@1RolesInstall`, &form))\n\tfmt.Println(\"successful RolesInstall \")\n\n\t//form = url.Values{\"SetDefault\": {\"yes\"}}\n\t//assert.NoError(t, postTx(`@1VotingTemplatesInstall`, &form))\n\t//fmt.Println(\"successful VotingTemplatesInstall \")\n\t//nodePub := `0498b18e551493a269b6f419d7784d26c8e3555638e80897c69997ef9f211e21d5d0b8adeeaab0e0e750e720ddf3048ec55d613ba5dee3fdfd4e7c17d346731e9b`\n\t//tcpHost := `127.0.0.1:7078`\n\t//firstNode := fmt.Sprintf(`{\"api_address\":\"%v\",\"public_key\":\"%v\",\"tcp_address\":\"%v\"}`, apiAddress, nodePub, tcpHost)\n\t//firstNodeID := `18`\n\t//form = url.Values{\"Conditions\": {`ContractConditions(\"@1DeveloperCondition\")`},\n\t//\t\"Id\":    {firstNodeID},\n\t//\t\"Value\": {firstNode},\n\t//}\n\t//assert.NoError(t, postTx(`@1EditAppParam`, &form))\n\t//fmt.Println(\"successful EditAppParam to first_node \")\n\t//users := []string{\n\t//\t`04794cbbfa0ff0d1a3dc3e08e5332ff44131be265d9d67ad60996fd5e3f04d50610b8de6b99bb068991a29806e16832290c0bc890373ae592037317fa213227e39`,\n\t//\t`045b9c7555a9218f67a94c54c740e33bac6658d6f19be3d527932ccf067cecea17d9d104c315f603458c4ff022af6234e6ee2c8772d334c6a4f478c25fd5ac9a81`,\n\t//\t`0432ed8601fbe0e452f647147e26bfbfc93532e019f9dad80d183c3dafe7d432f9d84cff6595d9c023fc40119f0b31fa3b2e05d6511bb83f1ba38eb487df8cafe1`,\n\t//\t`046ea9\n\t//\n\t////\t254d1d7a530794ef7f5798dcd7842829628ab3901f72b8ae3944d77403bdb9ac4cd286c664d7f247f83b88844bf4c1d3cc8990cd3944db49cf494cb277b3`,\n\t//}\n\t//for _, u := range users {\n\t//\tform = url.Values{\"NewPubkey\": {u}}\n\t//\tassert.NoError(t, postTx(`@1NewUser`, &form))\n\t//}\n\t//fmt.Println(\"successful 4 NewUser \")\n\t//form = url.Values{\n\t//\t\"TcpAddress\":  {`127.0.0.1:8078`},\n\t//\t\"ApiAddress\":  {`http://127.0.0.1:8079`},\n\t//\t\"PubKey\":      {`04794cbbfa0ff0d1a3dc3e08e5332ff44131be265d9d67ad60996fd5e3f04d50610b8de6b99bb068991a29806e16832290c0bc890373ae592037317fa213227e39`},\n\t//\t\"Description\": {`node2`}}\n\t//assert.NoError(t, postTx(`@1CNConnectionRequest`, &form))\n\t//fmt.Println(\"successful node2 CNConnectionRequest \")\n\t//form = url.Values{\n\t//\t\"TcpAddress\":  {`127.0.0.1:9078`},\n\t//\t\"ApiAddress\":  {`http://127.0.0.1:9079`},\n\t//\t\"PubKey\":      {`0432ed8601fbe0e452f647147e26bfbfc93532e019f9dad80d183c3dafe7d432f9d84cff6595d9c023fc40119f0b31fa3b2e05d6511bb83f1ba38eb487df8cafe1`},\n\t//\t\"Description\": {`node3`}}\n\t//assert.NoError(t, postTx(`@1CNConnectionRequest`, &form))\n\t//fmt.Println(\"successful node3 CNConnectionRequest \")\n}\n"
  },
  {
    "path": "packages/api/interface.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype componentModel interface {\n\tSetTablePrefix(prefix string)\n\tGet(name string) (bool, error)\n}\n\nfunc getPageRowHandler(w http.ResponseWriter, r *http.Request) {\n\tgetInterfaceRow(w, r, &sqldb.Page{})\n}\n\nfunc getMenuRowHandler(w http.ResponseWriter, r *http.Request) {\n\tgetInterfaceRow(w, r, &sqldb.Menu{})\n}\n\nfunc getSnippetRowHandler(w http.ResponseWriter, r *http.Request) {\n\tgetInterfaceRow(w, r, &sqldb.Snippet{})\n}\n\nfunc getInterfaceRow(w http.ResponseWriter, r *http.Request, c componentModel) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\n\tc.SetTablePrefix(client.Prefix())\n\tif ok, err := c.Get(params[\"name\"]); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting one row\")\n\t\terrorResponse(w, errQuery)\n\t\treturn\n\t} else if !ok {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tjsonResponse(w, c)\n}\n"
  },
  {
    "path": "packages/api/interface_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetInterfaceRow(t *testing.T) {\n\tcases := []struct {\n\t\turl        string\n\t\tcontract   string\n\t\tequalAttrs []string\n\t}{\n\t\t{\"interface/page/\", \"NewPage\", []string{\"Name\", \"Value\", \"Menu\", \"Conditions\"}},\n\t\t{\"interface/menu/\", \"NewMenu\", []string{\"Name\", \"Value\", \"Title\", \"Conditions\"}},\n\t\t{\"interface/snippet/\", \"NewSnippet\", []string{\"Name\", \"Value\", \"Conditions\"}},\n\t}\n\n\tcheckEqualAttrs := func(form url.Values, result map[string]any, equalKeys []string) {\n\t\tfor _, key := range equalKeys {\n\t\t\tv := result[strings.ToLower(key)]\n\t\t\tassert.EqualValues(t, form.Get(key), v)\n\t\t}\n\t}\n\n\terrUnauthorized := `401 {\"error\": \"E_UNAUTHORIZED\", \"msg\": \"Unauthorized\" }`\n\tfor _, c := range cases {\n\t\tassert.EqualError(t, sendGet(c.url+\"-\", &url.Values{}, nil), errUnauthorized)\n\t}\n\n\tassert.NoError(t, keyLogin(1))\n\n\tfor _, c := range cases {\n\t\tname := randName(\"component\")\n\t\tform := url.Values{\n\t\t\t\"Name\": {name}, \"Value\": {\"value\"}, \"Menu\": {\"default_menu\"}, \"Title\": {\"title\"},\n\t\t\t\"Conditions\": {\"true\"},\n\t\t}\n\t\tassert.NoError(t, postTx(c.contract, &form))\n\t\tresult := map[string]any{}\n\t\tassert.NoError(t, sendGet(c.url+name, &url.Values{}, &result))\n\t\tcheckEqualAttrs(form, result, c.equalAttrs)\n\t}\n}\n\nfunc TestNewMenuNoError(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\tmenuname := \"myTestMenu\"\n\tform := url.Values{\"Name\": {menuname}, \"Value\": {`first\n\t\tsecond\n\t\tthird`}, \"Title\": {`My Test Menu`},\n\t\t\"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewMenu`, &form))\n\n\terr := postTx(`NewMenu`, &form)\n\tassert.Equal(t, fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Menu %s already exists\"}`, menuname), cutErr(err))\n}\n\nfunc TestEditMenuNoError(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\tform := url.Values{\n\t\t\"Id\": {\"1\"},\n\t\t\"Value\": {`first\n\t\tsecond\n\t\tthird\n\t\tandmore`},\n\t\t\"Title\": {`My edited Test Menu`},\n\t}\n\tassert.NoError(t, postTx(`EditMenu`, &form))\n}\n\nfunc TestAppendMenuNoError(t *testing.T) {\n\trequire.NoError(t, keyLogin(1))\n\tform := url.Values{\n\t\t\"Id\":    {\"3\"},\n\t\t\"Value\": {\"appended item\"},\n\t}\n\n\tassert.NoError(t, postTx(\"AppendMenu\", &form))\n}\n"
  },
  {
    "path": "packages/api/lang_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestLang(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(\"lng\")\n\tutfName := randName(\"lngutf\")\n\n\terr := postTx(\"NewLang\", &url.Values{\n\t\t\"Name\":          {name},\n\t\t\"Trans\":         {`{\"en\": \"My test\", \"fr\": \"French string\", \"en-US\": \"US locale\"}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t})\n\tassert.NoError(t, err)\n\tvar list listResult\n\terr = sendGet(`list/languages`, nil, &list)\n\tif err != nil {\n\t\treturn\n\t}\n\tid := strconv.FormatInt(list.Count, 10)\n\n\tcases := []struct {\n\t\turl    string\n\t\tform   url.Values\n\t\texpect string\n\t}{\n\t\t{\n\t\t\t\"NewLang\",\n\t\t\turl.Values{\n\t\t\t\t\"Name\":          {utfName},\n\t\t\t\t\"Trans\":         {`{\"en\": \"test\"}`},\n\t\t\t\t\"ApplicationId\": {\"1\"},\n\t\t\t},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"NewPage\",\n\t\t\turl.Values{\n\t\t\t\t\"Name\":          {name},\n\t\t\t\t\"Value\":         {fmt.Sprintf(\"Span($@1%s$)\", name)},\n\t\t\t\t\"Menu\":          {\"default_menu\"},\n\t\t\t\t\"Conditions\":    {`ContractConditions(\"MainCondition\")`},\n\t\t\t\t\"ApplicationId\": {\"1\"},\n\t\t\t},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"content/page/\" + name,\n\t\t\turl.Values{\"lang\": {\"fr\"}},\n\t\t\t`[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"French string\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content/page/\" + name,\n\t\t\turl.Values{\"lang\": {\"en-GB\"}},\n\t\t\t`[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"My test\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content/page/\" + name,\n\t\t\turl.Values{\"lang\": {\"en-US\"}},\n\t\t\t`[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"US locale\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {\n\t\t\t\t\tfmt.Sprintf(`Div(){\n\t\t\t\t\t\tButton(Body: $%[1]s$ $,  Page:test).Alert(Text: $%[1]s$, ConfirmButton: $confirm$, CancelButton: $cancel$)\n\t\t\t\t\t\tButton(Body: LangRes(@1%[1]s) LangRes, PageParams: \"test\", ).Alert(Text: $%[1]s$, CancelButton: $cancel$)\n\t\t\t\t\t}`, utfName),\n\t\t\t\t},\n\t\t\t\t\"app_id\": {\"1\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"div\",\"children\":[{\"tag\":\"button\",\"attr\":{\"alert\":{\"cancelbutton\":\"$cancel$\",\"confirmbutton\":\"$confirm$\",\"text\":\"test\"},\"page\":\"test\"},\"children\":[{\"tag\":\"text\",\"text\":\"test $\"}]},{\"tag\":\"button\",\"attr\":{\"alert\":{\"cancelbutton\":\"$cancel$\",\"text\":\"test\"},\"pageparams\":{\"test\":{\"text\":\"test\",\"type\":\"text\"}}},\"children\":[{\"tag\":\"text\",\"text\":\"test\"},{\"tag\":\"text\",\"text\":\" LangRes\"}]}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t`template`: {fmt.Sprintf(`Span(Text LangRes(%s)+LangRes(%[1]s,fr))`, name)},\n\t\t\t\t`app_id`:   {`1`},\n\t\t\t},\n\t\t\t`[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"Text My test\"},{\"tag\":\"text\",\"text\":\"+French string\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {fmt.Sprintf(`Span(Text LangRes(%s)+LangRes(%[1]s,fr))`, name)},\n\t\t\t\t\"lang\":     {\"fr\"},\n\t\t\t\t\"app_id\":   {\"1\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"Text French string\"},{\"tag\":\"text\",\"text\":\"+French string\"}]}]`,\n\t\t},\n\t\t{\n\t\t\t\"EditLang\",\n\t\t\turl.Values{\n\t\t\t\t\"Id\":    {id},\n\t\t\t\t\"Trans\": {`{\"en\": \"My test\", \"fr\": \"French string\", \"es\": \"Spanish text\"}`},\n\t\t\t},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {fmt.Sprintf(`Table(mysrc,\"$%[1]s$=name\")Span(Text LangRes(%[1]s,es) $%[1]s$) Input(Class: form-control, Placeholder: $%[1]s$, Type: text, Name: Name)`, name)},\n\t\t\t\t\"app_id\":   {\"1\"},\n\t\t\t},\n\t\t\t`[{\"tag\":\"table\",\"attr\":{\"columns\":[{\"Name\":\"name\",\"Title\":\"My test\"}],\"source\":\"mysrc\"}},{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"Text Spanish text\"},{\"tag\":\"text\",\"text\":\" My test\"}]},{\"tag\":\"input\",\"attr\":{\"class\":\"form-control\",\"name\":\"Name\",\"placeholder\":\"My test\",\"type\":\"text\"}}]`,\n\t\t},\n\t\t{\n\t\t\t\"content\",\n\t\t\turl.Values{\n\t\t\t\t\"template\": {fmt.Sprintf(`MenuGroup($%s$){MenuItem(Ooops, ooops)}MenuGroup(nolang){MenuItem(no, no)}`, name)},\n\t\t\t\t\"app_id\":   {\"1\"},\n\t\t\t},\n\t\t\tfmt.Sprintf(`[{\"tag\":\"menugroup\",\"attr\":{\"name\":\"$%s$\",\"title\":\"My test\"},\"children\":[{\"tag\":\"menuitem\",\"attr\":{\"page\":\"ooops\",\"title\":\"Ooops\"}}]},{\"tag\":\"menugroup\",\"attr\":{\"name\":\"nolang\",\"title\":\"nolang\"},\"children\":[{\"tag\":\"menuitem\",\"attr\":{\"page\":\"no\",\"title\":\"no\"}}]}]`, name),\n\t\t},\n\t}\n\n\tfor _, v := range cases {\n\t\tvar ret contentResult\n\n\t\tif len(v.expect) == 0 {\n\t\t\tassert.NoError(t, postTx(v.url, &v.form))\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.NoError(t, sendPost(v.url, &v.form, &ret))\n\t\tassert.Equal(t, v.expect, RawToString(ret.Tree))\n\t}\n}\n"
  },
  {
    "path": "packages/api/limit_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nfunc TestLimit(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\trnd := randName(``)\n\tform := url.Values{\"Name\": {\"tbl\" + rnd}, \"Columns\": {`[{\"name\":\"name\",\"type\":\"number\",   \"conditions\":\"true\"},\n\t{\"name\":\"block\", \"type\":\"varchar\",\"conditions\":\"true\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tform = url.Values{`Value`: {`contract Limit` + rnd + ` {\n\t\tdata {\n\t\t\tNum int\n\t\t}\n\t\tconditions {\n\t\t}\n\t\taction {\n\t\t   DBInsert(\"tbl` + rnd + `\", {name: $Num, block: $block}) \n\t\t}\n\t}`}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{`Value`: {`contract Upd` + rnd + ` {\n\t\tdata {\n\t\t\tName string\n\t\t\tValue string\n\t\t}\n\t\tconditions {\n\t\t}\n\t\taction {\n\t\t   DBUpdatePlatformParam($Name, $Value, \"\") \n\t\t}\n\t}`}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tall := 10\n\tsendList := func() {\n\t\tfor i := 0; i < all; i++ {\n\t\t\tassert.NoError(t, postTx(`Limit`+rnd, &url.Values{\n\t\t\t\t`Num`:    {converter.IntToStr(i)},\n\t\t\t\t`nowait`: {`true`},\n\t\t\t}))\n\t\t}\n\t\ttime.Sleep(10 * time.Second)\n\t}\n\tcheckList := func(count, wantBlocks int) (err error) {\n\t\tvar list listResult\n\t\terr = sendGet(`list/tbl`+rnd, nil, &list)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif converter.StrToInt(strconv.FormatInt(list.Count, 10)) != count {\n\t\t\treturn fmt.Errorf(`wrong list items %d != %d`, list.Count, count)\n\t\t}\n\t\tblocks := make(map[string]int)\n\t\tfor _, item := range list.List {\n\t\t\tif v, ok := blocks[item[\"block\"]]; ok {\n\t\t\t\tblocks[item[\"block\"]] = v + 1\n\t\t\t} else {\n\t\t\t\tblocks[item[\"block\"]] = 1\n\t\t\t}\n\t\t}\n\t\tif wantBlocks > 0 && len(blocks) != wantBlocks {\n\t\t\treturn fmt.Errorf(`wrong number of blocks %d != %d`, len(blocks), wantBlocks)\n\t\t}\n\t\treturn nil\n\t}\n\tsendList()\n\tassert.NoError(t, checkList(10, 1))\n\n\tvar syspar paramsResult\n\tassert.NoError(t, sendGet(`systemparams?names=max_tx_block,max_tx_block_per_user`, nil, &syspar))\n\n\tvar maxusers, maxtx string\n\tif syspar.List[0].Name == \"max_tx_block\" {\n\t\tmaxusers = syspar.List[1].Value\n\t\tmaxtx = syspar.List[0].Value\n\t} else {\n\t\tmaxusers = syspar.List[0].Value\n\t\tmaxtx = syspar.List[1].Value\n\t}\n\trestoreMax := func() {\n\t\tassert.NoError(t, postTx(`Upd`+rnd, &url.Values{`Name`: {`max_tx_block`}, `Value`: {maxtx}}))\n\t\tassert.NoError(t, postTx(`Upd`+rnd, &url.Values{`Name`: {`max_tx_block_per_user`}, `Value`: {maxusers}}))\n\t}\n\tdefer restoreMax()\n\n\tassert.NoError(t, postTx(`Upd`+rnd, &url.Values{`Name`: {`max_tx_block`}, `Value`: {`7`}}))\n\n\tsendList()\n\tassert.NoError(t, checkList(20, 3))\n\tassert.NoError(t, postTx(`Upd`+rnd, &url.Values{`Name`: {`max_tx_block_per_user`}, `Value`: {`3`}}))\n\n\tsendList()\n\tassert.NoError(t, checkList(30, 7))\n\n\trestoreMax()\n\tassert.NoError(t, sendGet(`systemparams?names=max_block_generation_time`, nil, &syspar))\n\n\tvar maxtime string\n\tmaxtime = syspar.List[0].Value\n\tdefer func() {\n\t\tassert.NoError(t, postTx(`Upd`+rnd, &url.Values{\n\t\t\t`Name`:  {`max_block_generation_time`},\n\t\t\t`Value`: {maxtime},\n\t\t}))\n\t}()\n\tassert.NoError(t, postTx(`Upd`+rnd, &url.Values{`Name`: {`max_block_generation_time`}, `Value`: {`100`}}))\n\n\tsendList()\n\tassert.NoError(t, checkList(40, 0))\n}\n"
  },
  {
    "path": "packages/api/list.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\t\"github.com/IBAX-io/go-ibax/packages/template\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t//\"io/ioutil\"\n\t\"net/http\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype listResult struct {\n\tCount int64               `json:\"count\"`\n\tList  []map[string]string `json:\"list\"`\n}\n\ntype sumResult struct {\n\tSum string `json:\"sum\"`\n}\n\ntype listForm struct {\n\tpaginatorForm\n\trowForm\n}\n\ntype listWhereForm struct {\n\tlistForm\n\tOrder   string `schema:\"order\"`\n\tInWhere string `schema:\"where\"`\n}\n\ntype SumWhereForm struct {\n\tColumn string `schema:\"column\"`\n\tWhere  string `schema:\"where\"`\n}\n\nfunc (f *listForm) Validate(r *http.Request) error {\n\tif err := f.paginatorForm.Validate(r); err != nil {\n\t\treturn err\n\t}\n\treturn f.rowForm.Validate(r)\n}\n\nfunc (f *SumWhereForm) Validate(r *http.Request) error {\n\tif len(f.Column) > 0 {\n\t\tf.Column = converter.Sanitize(f.Column, ``)\n\t}\n\treturn nil\n}\n\nfunc checkAccess(tableName, columns string, client *Client) (table string, cols string, err error) {\n\tsc := smart.SmartContract{\n\t\tCLB: conf.Config.IsSupportingCLB(),\n\t\tVM:  script.GetVM(),\n\t\tTxSmart: &types.SmartTransaction{\n\t\t\tHeader: &types.Header{\n\t\t\t\tEcosystemID: client.EcosystemID,\n\t\t\t\tKeyID:       client.KeyID,\n\t\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t\t},\n\t\t},\n\t}\n\ttable, _, cols, err = sc.CheckAccess(tableName, columns, client.EcosystemID)\n\treturn\n}\n\nfunc getListHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &listForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tvar (\n\t\terr   error\n\t\ttable string\n\t)\n\ttable, form.Columns, err = checkAccess(params[\"name\"], form.Columns, client)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tq := sqldb.GetTableQuery(params[\"name\"], client.EcosystemID)\n\n\tif len(form.Columns) > 0 {\n\t\tq = q.Select(\"id,\" + form.Columns)\n\t}\n\n\tresult := new(listResult)\n\terr = q.Count(&result.Count).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting table records count\")\n\t\terrorResponse(w, errTableNotFound.Errorf(table))\n\t\treturn\n\t}\n\n\trows, err := q.Order(\"id ASC\").Offset(form.Offset).Limit(form.Limit).Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tresult.List, err = sqldb.GetResult(rows)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, result)\n}\n\nfunc getListWhereHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &listWhereForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tvar (\n\t\terr                 error\n\t\ttable, where, order string\n\t)\n\ttable, form.Columns, err = checkAccess(params[\"name\"], form.Columns, client)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tif form.Order != \"\" {\n\t\tvar orderParam any\n\t\terr = json.Unmarshal([]byte(form.Order), &orderParam)\n\t\tif err != nil {\n\t\t\terrorResponse(w, fmt.Errorf(\"order unamrshal:%v\", err))\n\t\t\treturn\n\t\t}\n\t\torder, err = qb.GetOrder(table, orderParam, true)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\t//q := sqldb.GetTableQuery(params[\"name\"], client.EcosystemID)\n\tq := sqldb.GetTableListQuery(params[\"name\"], client.EcosystemID)\n\tif len(form.Columns) > 0 {\n\t\tq = q.Select(\"id,\" + smart.PrepareColumns([]string{form.Columns}))\n\t}\n\n\tif len(form.InWhere) > 0 {\n\t\tinWhere, _, err := template.ParseObject([]rune(form.InWhere))\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tswitch v := inWhere.(type) {\n\t\tcase string:\n\t\t\tif len(v) == 0 {\n\t\t\t\twhere = `true`\n\t\t\t} else {\n\t\t\t\terrorResponse(w, errors.New(`Where has wrong format`))\n\t\t\t\treturn\n\t\t\t}\n\t\tcase map[string]any:\n\t\t\twhere, err = qb.GetWhere(types.LoadMap(v))\n\t\t\tif err != nil {\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase *types.Map:\n\t\t\twhere, err = qb.GetWhere(v)\n\t\t\tif err != nil {\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\terrorResponse(w, errors.New(`Where has wrong format`))\n\t\t\treturn\n\t\t}\n\t\tq = q.Where(where)\n\t}\n\n\tresult := new(listResult)\n\terr = q.Count(&result.Count).Error\n\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).\n\t\t\tErrorf(\"selecting rows from table %s select %s where %s\", table, smart.PrepareColumns([]string{form.Columns}), where)\n\t\terrorResponse(w, errTableNotFound.Errorf(table))\n\t\treturn\n\t}\n\n\tif len(order) > 0 {\n\t\trows, err := q.Order(order).Offset(form.Offset).Limit(form.Limit).Rows()\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tresult.List, err = sqldb.GetResult(rows)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t} else {\n\t\trows, err := q.Order(\"id ASC\").Offset(form.Offset).Limit(form.Limit).Rows()\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tresult.List, err = sqldb.GetResult(rows)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tjsonResponse(w, result)\n}\n\nfunc getsumWhereHandler(w http.ResponseWriter, r *http.Request) {\n\tvar (\n\t\terr          error\n\t\ttable, where string\n\t)\n\tform := &SumWhereForm{}\n\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\ttable, form.Column, err = checkAccess(params[\"name\"], form.Column, client)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\t//q := sqldb.GetTableQuery(params[\"name\"], client.EcosystemID)\n\t//\n\t//if len(form.Columns) > 0 {\n\t//\tq = q.Select(\"id,\" + smart.PrepareColumns([]string{form.Columns}))\n\t//}\n\n\tif len(form.Where) > 0 {\n\t\tinWhere, _, err := template.ParseObject([]rune(form.Where))\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tswitch v := inWhere.(type) {\n\t\tcase string:\n\t\t\tif len(v) == 0 {\n\t\t\t\twhere = `true`\n\t\t\t} else {\n\t\t\t\terrorResponse(w, errors.New(`Where has wrong format`))\n\t\t\t\treturn\n\t\t\t}\n\t\tcase map[string]any:\n\t\t\twhere, err = qb.GetWhere(types.LoadMap(v))\n\t\t\tif err != nil {\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase *types.Map:\n\t\t\twhere, err = qb.GetWhere(v)\n\t\t\tif err != nil {\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\terrorResponse(w, errors.New(`Where has wrong format`))\n\t\t\treturn\n\t\t}\n\t\t//q = q.Where(where)\n\t}\n\n\tcount, err := sqldb.NewDbTransaction(nil).GetSumColumnCount(table, form.Column, where)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Errorf(\"selecting rows from table %s select %s where %s\", table, smart.PrepareColumns([]string{form.Column}), where)\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tresult := new(sumResult)\n\tif count > 0 {\n\t\tsum, err := sqldb.NewDbTransaction(nil).GetSumColumn(table, form.Column, where)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).\n\t\t\t\tErrorf(\"selecting rows from table %s select %s where %s\", table, smart.PrepareColumns([]string{form.Column}), where)\n\t\t\terrorResponse(w, errTableNotFound.Errorf(table))\n\t\t\treturn\n\t\t}\n\t\tresult.Sum = sum\n\t}\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/list_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nfunc TestList(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret listResult\n\terr := sendGet(`list/contracts`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif converter.StrToInt64(strconv.FormatInt(ret.Count, 10)) < 7 {\n\t\tt.Error(fmt.Errorf(`The number of records %d < 7`, ret.Count))\n\t\treturn\n\t}\n\terr = sendGet(`list/qwert`, nil, &ret)\n\tif err.Error() != `404 {\"error\":\"E_TABLENOTFOUND\",\"msg\":\"Table 1_qwert has not been found\"}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar retTable tableResult\n\tfor _, item := range []string{`app_params`, `parameters`} {\n\t\terr = sendGet(`table/`+item, nil, &retTable)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tif retTable.Name != item {\n\t\t\tt.Errorf(`wrong table name %s != %s`, retTable.Name, item)\n\t\t\treturn\n\t\t}\n\t}\n\tvar sec listResult\n\terr = sendGet(`sections`, nil, &sec)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif sec.Count == 0 {\n\t\tt.Errorf(`section error`)\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "packages/api/login.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/publisher\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/golang-jwt/jwt/v4\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Special word used by frontend to sign UID generated by /getuid API command, sign is performed for contcatenated word and UID\nfunc nonceSalt() string {\n\treturn fmt.Sprintf(\"LOGIN%d\", conf.Config.LocalConf.NetworkID)\n}\n\ntype loginForm struct {\n\tEcosystemID int64          `schema:\"ecosystem\"`\n\tExpire      int64          `schema:\"expire\"`\n\tPublicKey   publicKeyValue `schema:\"pubkey\"`\n\tKeyID       string         `schema:\"key_id\"`\n\tSignature   hexValue       `schema:\"signature\"`\n\tRoleID      int64          `schema:\"role_id\"`\n}\n\ntype publicKeyValue struct {\n\thexValue\n}\n\nfunc (pk *publicKeyValue) UnmarshalText(v []byte) (err error) {\n\tpk.value, err = hex.DecodeString(string(v))\n\tpk.value = crypto.CutPub(pk.value)\n\treturn\n}\n\nfunc (f *loginForm) Validate(r *http.Request) error {\n\tif f.Expire == 0 {\n\t\tf.Expire = int64(jwtExpire)\n\t}\n\n\treturn nil\n}\n\ntype loginResult struct {\n\tToken       string        `json:\"token,omitempty\"`\n\tEcosystemID string        `json:\"ecosystem_id,omitempty\"`\n\tKeyID       string        `json:\"key_id,omitempty\"`\n\tAccount     string        `json:\"account,omitempty\"`\n\tNotifyKey   string        `json:\"notify_key,omitempty\"`\n\tIsNode      bool          `json:\"isnode\"`\n\tIsOwner     bool          `json:\"isowner\"`\n\tIsCLB       bool          `json:\"clb\"`\n\tTimestamp   string        `json:\"timestamp,omitempty\"`\n\tRoles       []rolesResult `json:\"roles,omitempty\"`\n}\n\ntype rolesResult struct {\n\tRoleID   int64  `json:\"role_id\"`\n\tRoleName string `json:\"role_name\"`\n}\n\nfunc (m Mode) loginHandler(w http.ResponseWriter, r *http.Request) {\n\tvar (\n\t\tpublicKey           []byte\n\t\twallet, founder, fm int64\n\t\tuid                 string\n\t\terr                 error\n\t\tisExistPub          bool\n\t\tform                = new(loginForm)\n\t\tspfounder, spfm     sqldb.StateParameter\n\t)\n\tif uid, err = getUID(r); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif err = parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tif form.EcosystemID > 0 {\n\t\tclient.EcosystemID = form.EcosystemID\n\t} else if client.EcosystemID == 0 {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Warning(\"state is empty, using 1 as a state\")\n\t\tclient.EcosystemID = 1\n\t}\n\n\tif len(form.KeyID) > 0 {\n\t\twallet = converter.StringToAddress(form.KeyID)\n\t} else if len(form.PublicKey.Bytes()) > 0 {\n\t\twallet = crypto.Address(form.PublicKey.Bytes())\n\t}\n\n\taccount := &sqldb.Key{}\n\taccount.SetTablePrefix(client.EcosystemID)\n\tisAccount, err := account.Get(nil, wallet)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting public key from keys\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tspfm.SetTablePrefix(converter.Int64ToStr(client.EcosystemID))\n\tif ok, err := spfm.Get(nil, \"free_membership\"); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting free_membership parameter\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t} else if ok {\n\t\tfm = converter.StrToInt64(spfm.Value)\n\t}\n\tpublicKey = account.PublicKey\n\tisExistPub = len(publicKey) == 0\n\n\tisCan := func(a, e bool) bool {\n\t\treturn !a || (a && e)\n\t}\n\tif isCan(isAccount, isExistPub) {\n\t\tif !(fm == 1 || client.EcosystemID == 1) {\n\t\t\terrorResponse(w, errEcoNotOpen.Errorf(client.EcosystemID))\n\t\t\treturn\n\t\t}\n\t}\n\n\tif isAccount && !isExistPub {\n\t\tif account.Deleted == 1 {\n\t\t\terrorResponse(w, errDeletedKey)\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tif !allowCreateUser(client) {\n\t\t\terrorResponse(w, errKeyNotFound)\n\t\t\treturn\n\t\t}\n\t\tif isCan(isAccount, isExistPub) {\n\n\t\t\tpublicKey = form.PublicKey.Bytes()\n\t\t\tif len(publicKey) == 0 {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty\")\n\t\t\t\terrorResponse(w, errEmptyPublic)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tnodePrivateKey := syspar.GetNodePrivKey()\n\n\t\t\tcontract := smart.GetContract(\"NewUser\", 1)\n\t\t\tsc := types.SmartTransaction{\n\t\t\t\tHeader: &types.Header{\n\t\t\t\t\tID:          int(contract.Info().ID),\n\t\t\t\t\tEcosystemID: 1,\n\t\t\t\t\tTime:        time.Now().Unix(),\n\t\t\t\t\tKeyID:       conf.Config.KeyID,\n\t\t\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t\t\t},\n\t\t\t\tParams: map[string]any{\n\t\t\t\t\t\"NewPubkey\": hex.EncodeToString(publicKey),\n\t\t\t\t\t\"Ecosystem\": client.EcosystemID,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tstp := &transaction.SmartTransactionParser{\n\t\t\t\tSmartContract: &smart.SmartContract{TxSmart: new(types.SmartTransaction)},\n\t\t\t}\n\t\t\ttxData, err := stp.BinMarshalWithPrivate(&sc, nodePrivateKey, true)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ContractError, \"err\": err}).Error(\"Building transaction\")\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif err := m.ContractRunner.RunContract(txData, stp.Hash, sc.KeyID, stp.Timestamp, logger); err != nil {\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !conf.Config.IsSupportingCLB() {\n\t\t\t\tgt := 3 * syspar.GetMaxBlockGenerationTime()\n\t\t\t\tl := &sqldb.LogTransaction{}\n\t\t\t\tfor i := 0; i < 2; i++ {\n\t\t\t\t\tfound, err := l.GetByHash(nil, stp.Hash)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\terrorResponse(w, err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif found {\n\t\t\t\t\t\tif l.Status != 0 {\n\t\t\t\t\t\t\terrorResponse(w, errors.New(`encountered some problems when login account`))\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t_, _ = account.Get(nil, wallet)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(time.Duration(gt) * time.Millisecond)\n\t\t\t\t}\n\n\t\t\t\tif l.Block == 0 {\n\t\t\t\t\terrorResponse(w, errNewUser)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty, and state is not default\")\n\t\t\terrorResponse(w, errStateLogin.Errorf(wallet, client.EcosystemID))\n\t\t\treturn\n\t\t}\n\t}\n\n\tif len(publicKey) == 0 {\n\t\tif client.EcosystemID > 1 {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty, and state is not default\")\n\t\t\terrorResponse(w, errStateLogin.Errorf(wallet, client.EcosystemID))\n\t\t\treturn\n\t\t}\n\n\t\tif len(form.PublicKey.Bytes()) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty\")\n\t\t\terrorResponse(w, errEmptyPublic)\n\t\t\treturn\n\t\t}\n\t}\n\n\tif form.RoleID != 0 && client.RoleID == 0 {\n\t\tcheckedRole, err := checkRoleFromParam(form.RoleID, client.EcosystemID, account.AccountID)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\n\t\tif checkedRole != form.RoleID {\n\t\t\terrorResponse(w, errCheckRole)\n\t\t\treturn\n\t\t}\n\n\t\tclient.RoleID = checkedRole\n\t}\n\n\tverify, err := crypto.Verify(publicKey, []byte(nonceSalt()+uid), form.Signature.Bytes())\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.CryptoError, \"pubkey\": publicKey, \"uid\": uid, \"signature\": form.Signature.Bytes()}).Info(\"checking signature\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif !verify {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.InvalidObject, \"pubkey\": publicKey, \"uid\": uid, \"signature\": form.Signature.Bytes()}).Error(\"incorrect signature\")\n\t\terrorResponse(w, errSignature)\n\t\treturn\n\t}\n\n\tspfounder.SetTablePrefix(converter.Int64ToStr(client.EcosystemID))\n\tif ok, err := spfounder.Get(nil, \"founder_account\"); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting founder_account parameter\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t} else if ok {\n\t\tfounder = converter.StrToInt64(spfounder.Value)\n\t}\n\n\tresult := &loginResult{\n\t\tAccount:     account.AccountID,\n\t\tEcosystemID: converter.Int64ToStr(client.EcosystemID),\n\t\tKeyID:       converter.Int64ToStr(wallet),\n\t\tIsOwner:     founder == wallet,\n\t\tIsNode:      conf.Config.KeyID == wallet,\n\t\tIsCLB:       conf.Config.IsSupportingCLB(),\n\t}\n\n\tclaims := JWTClaims{\n\t\tKeyID:       result.KeyID,\n\t\tAccountID:   account.AccountID,\n\t\tEcosystemID: result.EcosystemID,\n\t\tRoleID:      converter.Int64ToStr(form.RoleID),\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\tExpiresAt: &jwt.NumericDate{Time: time.Now().Add(time.Second * time.Duration(form.Expire))},\n\t\t},\n\t}\n\n\tresult.Token, err = generateJWTToken(claims)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JWTError, \"error\": err}).Error(\"generating jwt token\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tresult.NotifyKey, result.Timestamp, err = publisher.GetJWTCent(wallet, form.Expire)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tra := &sqldb.RolesParticipants{}\n\troles, err := ra.SetTablePrefix(client.EcosystemID).GetActiveMemberRoles(account.AccountID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting roles\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tfor _, r := range roles {\n\t\tvar res map[string]string\n\t\tif err := json.Unmarshal([]byte(r.Role), &res); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling role\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\n\t\tresult.Roles = append(result.Roles, rolesResult{\n\t\t\tRoleID:   converter.StrToInt64(res[\"id\"]),\n\t\t\tRoleName: res[\"name\"],\n\t\t})\n\t}\n\n\tjsonResponse(w, result)\n}\n\nfunc getUID(r *http.Request) (string, error) {\n\tvar uid string\n\n\ttoken := getToken(r)\n\tif token != nil {\n\t\tif claims, ok := token.Claims.(*JWTClaims); ok {\n\t\t\tuid = claims.UID\n\t\t}\n\t} else if len(uid) == 0 {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Warning(\"UID is empty\")\n\t\treturn \"\", errUnknownUID\n\t}\n\n\treturn uid, nil\n}\n\nfunc checkRoleFromParam(role, ecosystemID int64, account string) (int64, error) {\n\tif role > 0 {\n\t\tok, err := sqldb.MemberHasRole(nil, role, ecosystemID, account)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\"type\":      consts.DBError,\n\t\t\t\t\"account\":   account,\n\t\t\t\t\"role\":      role,\n\t\t\t\t\"ecosystem\": ecosystemID}).Error(\"check role\")\n\n\t\t\treturn 0, err\n\t\t}\n\n\t\tif !ok {\n\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\"type\":      consts.NotFound,\n\t\t\t\t\"account\":   account,\n\t\t\t\t\"role\":      role,\n\t\t\t\t\"ecosystem\": ecosystemID,\n\t\t\t}).Error(\"member hasn't role\")\n\n\t\t\treturn 0, nil\n\t\t}\n\t}\n\treturn role, nil\n}\n\nfunc allowCreateUser(c *Client) bool {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn true\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "packages/api/member.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc getAvatarHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\taccount := params[\"account\"]\n\tecosystemID := converter.StrToInt64(params[\"ecosystem\"])\n\n\tmember := &sqldb.Member{}\n\tmember.SetTablePrefix(converter.Int64ToStr(ecosystemID))\n\n\tfound, err := member.Get(account)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\n\t\t\t\"type\":      consts.DBError,\n\t\t\t\"error\":     err,\n\t\t\t\"ecosystem\": ecosystemID,\n\t\t\t\"account\":   account,\n\t\t}).Error(\"getting member\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif !found {\n\t\terrorResponse(w, errNotFoundRecord)\n\t\treturn\n\t}\n\n\tif member.ImageID == nil {\n\t\terrorResponse(w, errNotFoundRecord)\n\t\treturn\n\t}\n\n\tbin := &sqldb.Binary{}\n\tbin.SetTablePrefix(converter.Int64ToStr(ecosystemID))\n\tfound, err = bin.GetByID(*member.ImageID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"image_id\": *member.ImageID}).Errorf(\"on getting binary by id\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif !found {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tif len(bin.Data) == 0 {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject, \"error\": err, \"image_id\": *member.ImageID}).Errorf(\"on check avatar size\")\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", bin.MimeType)\n\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(bin.Data)))\n\tif _, err := w.Write(bin.Data); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"unable to write image\")\n\t}\n}\n\nfunc getMemberHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\n\taccount := params[\"account\"]\n\tecosystemID := converter.StrToInt64(params[\"ecosystem\"])\n\n\tmember := &sqldb.Member{}\n\tmember.SetTablePrefix(converter.Int64ToStr(ecosystemID))\n\n\t_, err := member.Get(account)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\n\t\t\t\"type\":      consts.DBError,\n\t\t\t\"error\":     err,\n\t\t\t\"ecosystem\": ecosystemID,\n\t\t\t\"account\":   account,\n\t\t}).Error(\"getting member\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, member)\n}\n"
  },
  {
    "path": "packages/api/metrics.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"runtime\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\n\t\"github.com/gorilla/mux\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype blockMetric struct {\n\tCount int64 `json:\"count\"`\n}\n\ntype blockMetricByNode struct {\n\tTotalCount   int64 `json:\"totalcount\"`\n\tPartialCount int64 `json:\"partialcount\"`\n}\n\ntype txMetric struct {\n\tCount int64 `json:\"count\"`\n}\n\ntype ecosysMetric struct {\n\tCount int64 `json:\"count\"`\n}\n\ntype keyMetric struct {\n\tCount int64 `json:\"count\"`\n}\n\ntype honorNodeMetric struct {\n\tCount int64 `json:\"count\"`\n}\n\ntype memMetric struct {\n\tAlloc uint64 `json:\"alloc\"`\n\tSys   uint64 `json:\"sys\"`\n}\n\ntype banMetric struct {\n\tNodePosition int  `json:\"node_position\"`\n\tStatus       bool `json:\"status\"`\n}\n\nfunc blocksCountHandler(w http.ResponseWriter, r *http.Request) {\n\tb := &sqldb.BlockChain{}\n\tlogger := getLogger(r)\n\n\tfound, err := b.GetMaxBlock()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"on getting max block\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif !found {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tbm := blockMetric{Count: b.ID}\n\tjsonResponse(w, bm)\n}\n\nfunc blocksCountByNodeHandler(w http.ResponseWriter, r *http.Request) {\n\tb := &sqldb.BlockChain{}\n\tlogger := getLogger(r)\n\tparams := mux.Vars(r)\n\tnodeId := converter.StrToInt64(params[\"node\"])\n\tmode := converter.StrToInt64(params[\"mode\"])\n\tif mode != consts.CandidateNodeMode && mode != consts.HonorNodeMode {\n\t\terrorResponse(w, errParamNotFound.Errorf(\"mode\"))\n\t\treturn\n\t}\n\n\tfound, err := b.GetMaxBlock()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"on getting max block\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif !found {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tc, err := sqldb.GetBlockCountByNode(nodeId, int32(mode))\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting block count by node\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tbm := blockMetricByNode{TotalCount: b.ID, PartialCount: c}\n\n\tjsonResponse(w, bm)\n}\n\nfunc txCountHandler(w http.ResponseWriter, r *http.Request) {\n\tc, err := sqldb.GetTxCount()\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting tx count\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tjsonResponse(w, txMetric{Count: c})\n}\n\nfunc ecosysCountHandler(w http.ResponseWriter, r *http.Request) {\n\ttotal, err := sqldb.GetAllSystemCount()\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithError(err).Error(\"on getting ecosystem count\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tjsonResponse(w, ecosysMetric{Count: total})\n}\n\nfunc keysCountHandler(w http.ResponseWriter, r *http.Request) {\n\tcnt, err := sqldb.GetKeysCount()\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting keys count\")\n\t\terrorResponse(w, err, http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tjsonResponse(w, keyMetric{Count: cnt})\n}\n\nfunc honorNodesCountHandler(w http.ResponseWriter, _ *http.Request) {\n\tfnMetric := honorNodeMetric{\n\t\tCount: syspar.GetNumberOfNodesFromDB(nil),\n\t}\n\n\tjsonResponse(w, fnMetric)\n}\n\nfunc memStatHandler(w http.ResponseWriter, _ *http.Request) {\n\tvar m runtime.MemStats\n\truntime.ReadMemStats(&m)\n\n\tjsonResponse(w, memMetric{Alloc: m.Alloc, Sys: m.Sys})\n}\n\nfunc banStatHandler(w http.ResponseWriter, _ *http.Request) {\n\tnodes := syspar.GetNodes()\n\tlist := make([]banMetric, 0, len(nodes))\n\n\tb := node.GetNodesBanService()\n\tfor i, n := range nodes {\n\t\tlist = append(list, banMetric{\n\t\t\tNodePosition: i,\n\t\t\tStatus:       b.IsBanned(n),\n\t\t})\n\t}\n\n\tjsonResponse(w, list)\n}\n"
  },
  {
    "path": "packages/api/middlewares.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"runtime/debug\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/statsd\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc authRequire(next func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\tclient := getClient(r)\n\t\tif client != nil && client.KeyID != 0 {\n\t\t\tnext(w, r)\n\t\t\treturn\n\t\t}\n\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Debug(\"wallet is empty\")\n\t\terrorResponse(w, errUnauthorized)\n\t}\n}\n\nfunc loggerFromRequest(r *http.Request) *log.Entry {\n\treturn log.WithFields(log.Fields{\n\t\t\"headers\":  r.Header,\n\t\t\"path\":     r.URL.Path,\n\t\t\"protocol\": r.Proto,\n\t\t\"remote\":   r.RemoteAddr,\n\t})\n}\nfunc loggerMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tlogger := loggerFromRequest(r)\n\t\tlogger.Info(\"received http request\")\n\t\tr = setLogger(r, logger)\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc recoverMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tlogger := getLogger(r)\n\t\t\t\tlogger.WithFields(log.Fields{\n\t\t\t\t\t\"type\":  consts.PanicRecoveredError,\n\t\t\t\t\t\"error\": err,\n\t\t\t\t\t\"stack\": string(debug.Stack()),\n\t\t\t\t}).Debug(\"panic recovered error\")\n\t\t\t\tfmt.Println(\"API Recovered\", fmt.Sprintf(\"%s: %s\", err, debug.Stack()))\n\t\t\t\terrorResponse(w, errRecovered)\n\t\t\t}\n\t\t}()\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc nodeStateMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar reason errType\n\t\tswitch node.NodePauseType() {\n\t\tcase node.NoPause:\n\t\t\tnext.ServeHTTP(w, r)\n\t\t\treturn\n\t\tcase node.PauseTypeUpdatingBlockchain:\n\t\t\tvar s sqldb.BlockChain\n\t\t\ts.GetMaxBlock()\n\t\t\treason = errUpdating.Errorf(s.ID)\n\t\t\tbreak\n\t\tcase node.PauseTypeStopingNetwork:\n\t\t\treason = errStopping\n\t\t\tbreak\n\t\t}\n\t\terrorResponse(w, reason)\n\t})\n}\n\nfunc tokenMiddleware(next http.Handler) http.Handler {\n\tconst authHeader = \"AUTHORIZATION\"\n\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t//token, err := RefreshToken(r.Header.Get(authHeader))\n\t\ttoken, err := parseJWTToken(r.Header.Get(authHeader))\n\t\tif err != nil {\n\t\t\tlogger := getLogger(r)\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JWTError, \"error\": err}).Warning(\"starting session\")\n\t\t}\n\t\tif token != nil && token.Valid {\n\t\t\tr = setToken(r, token)\n\t\t}\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc (m Mode) clientMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\ttoken := getToken(r)\n\t\tvar client *Client\n\t\tif token != nil { // get client from token\n\t\t\tvar err error\n\t\t\tif client, err = getClientFromToken(token, m.EcosystemGetter); err != nil {\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif client == nil {\n\t\t\t// create client with default ecosystem\n\t\t\tclient = &Client{EcosystemID: 1}\n\t\t}\n\t\tr = setClient(r, client)\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc statsdMiddleware(next http.Handler) http.Handler {\n\tconst v = 1.0\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\troute := mux.CurrentRoute(r)\n\n\t\tcounterName := statsd.APIRouteCounterName(r.Method, route.GetName())\n\t\tstatsd.Client.Inc(counterName+statsd.Count, 1, v)\n\t\tstartTime := time.Now()\n\n\t\tdefer func() {\n\t\t\tstatsd.Client.TimingDuration(counterName+statsd.Time, time.Since(startTime), v)\n\t\t}()\n\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n"
  },
  {
    "path": "packages/api/network.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\ntype HonorNodeJSON struct {\n\tTCPAddress string `json:\"tcp_address\"`\n\tAPIAddress string `json:\"api_address\"`\n\tPublicKey  string `json:\"public_key\"`\n\tUnbanTime  string `json:\"unban_time\"`\n\tStopped    bool   `json:\"stopped\"`\n}\n\ntype NetworkResult struct {\n\tNetworkID     string          `json:\"network_id\"`\n\tCentrifugoURL string          `json:\"centrifugo_url\"`\n\tTest          bool            `json:\"test\"`\n\tPrivate       bool            `json:\"private\"`\n\tHonorNodes    []HonorNodeJSON `json:\"honor_nodes\"`\n}\n\nfunc GetNodesJSON() []HonorNodeJSON {\n\tnodes := make([]HonorNodeJSON, 0)\n\tfor _, node := range syspar.GetNodes() {\n\t\tnodes = append(nodes, HonorNodeJSON{\n\t\t\tTCPAddress: node.TCPAddress,\n\t\t\tAPIAddress: node.APIAddress,\n\t\t\tPublicKey:  crypto.PubToHex(node.PublicKey),\n\t\t\tUnbanTime:  strconv.FormatInt(node.UnbanTime.Unix(), 10),\n\t\t})\n\t}\n\treturn nodes\n}\n\nfunc getNetworkHandler(w http.ResponseWriter, r *http.Request) {\n\tjsonResponse(w, &NetworkResult{\n\t\tNetworkID:     converter.Int64ToStr(conf.Config.LocalConf.NetworkID),\n\t\tCentrifugoURL: conf.Config.Centrifugo.URL,\n\t\tTest:          syspar.IsTestMode(),\n\t\tPrivate:       syspar.IsPrivateBlockchain(),\n\t\tHonorNodes:    GetNodesJSON(),\n\t})\n}\n"
  },
  {
    "path": "packages/api/node.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n)\n\n// nodeContract is used when calling a cron contract in CLB mode\nfunc nodeContractHandler(w http.ResponseWriter, r *http.Request) {\n\terrorResponse(w, errNotImplemented)\n}\n"
  },
  {
    "path": "packages/api/platform_params.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc getPlatformParamsHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &paramsForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tlogger := getLogger(r)\n\n\tlist, err := sqldb.GetAllPlatformParameters(nil, nil, nil, nil)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting all platform parameters\")\n\t}\n\n\tresult := &paramsResult{\n\t\tList: make([]paramResult, 0),\n\t}\n\n\tacceptNames := form.AcceptNames()\n\tfor _, item := range list {\n\t\tif len(acceptNames) > 0 && !acceptNames[item.Name] {\n\t\t\tcontinue\n\t\t}\n\t\tresult.List = append(result.List, paramResult{\n\t\t\tID:         converter.Int64ToStr(item.ID),\n\t\t\tName:       item.Name,\n\t\t\tValue:      item.Value,\n\t\t\tConditions: item.Conditions,\n\t\t})\n\t}\n\n\tif len(result.List) == 0 {\n\t\terrorResponse(w, errParamNotFound.Errorf(form.Names), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/read_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRead(t *testing.T) {\n\tvar (\n\t\tretCont contentResult\n\t)\n\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`tbl`)\n\tform := url.Values{\"Name\": {name}, \"ApplicationId\": {`1`},\n\t\t\"Columns\": {`[{\"name\":\"my\",\"type\":\"varchar\", \"index\": \"1\", \n\t  \"conditions\":\"true\"},\n\t{\"name\":\"amount\", \"type\":\"number\",\"index\": \"0\", \"conditions\":\"{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"true\\\"}\"},\n\t{\"name\":\"active\", \"type\":\"character\",\"index\": \"0\", \"conditions\":\"{\\\"update\\\":\\\"true\\\", \\\"read\\\":\\\"false\\\"}\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"read\": \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tcontList := []string{`contract %s {\n\t\taction {\n\t\t\tDBInsert(\"%[1]s\", {my: \"Alex\",amount: 100})\n\t\t\tDBInsert(\"%[1]s\", {my: \"Alex 2\",amount: 13300})\n\t\t\tDBInsert(\"%[1]s\", {my: \"Mike\",amount: 0})\n\t\t\tDBInsert(\"%[1]s\", {my: \"Mike 2\",amount: 25500})\n\t\t\tDBInsert(\"%[1]s\", {my: \"John Mike\", amount: 0})\n\t\t\tDBInsert(\"%[1]s\", {my: \"Serena Martin\",amount:777})\n\t\t}\n\t}`,\n\t\t`contract Get%s {\n\t\taction {\n\t\t\tvar row array\n\t\t\trow = DBFind(\"%[1]s\").Where({id:[{$gte: 2},{\"$lte\":5}]})\n\t\t}\n\t}`,\n\t\t`contract GetOK%s {\n\t\taction {\n\t\t\tvar row array\n\t\t\trow = DBFind(\"%[1]s\").Columns(\"my,amount\").Where({id:[{$gte: 2},{\"$lte\":5}]})\n\t\t}\n\t}`,\n\t\t`contract GetData%s {\n\t\taction {\n\t\t\tvar row array\n\t\t\trow = DBFind(\"%[1]s\").Columns(\"active\").Where({id:[{$gte: 2},{\"$lte\":5}]})\n\t\t}\n\t}`,\n\t\t`func ReadFilter%s bool {\n\t\t\t\tvar i int\n\t\t\t\tvar row map\n\t\t\t\twhile i < Len($data) {\n\t\t\t\t\trow = $data[i]\n\t\t\t\t\tif i == 1 || i == 3 {\n\t\t\t\t\t\trow[\"my\"] = \"No name\"\n\t\t\t\t\t\t$data[i] = row\n\t\t\t\t\t}\n\t\t\t\t\ti = i+ 1\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t}`,\n\t}\n\tfor _, contract := range contList {\n\t\tform = url.Values{\"Value\": {fmt.Sprintf(contract, name)}, \"ApplicationId\": {`1`},\n\t\t\t\"Conditions\": {`true`}}\n\t\tassert.NoError(t, postTx(`NewContract`, &form))\n\t}\n\tassert.NoError(t, postTx(name, &url.Values{}))\n\n\tassert.EqualError(t, postTx(`GetData`+name, &url.Values{}), `{\"type\":\"panic\",\"error\":\"Access denied\"}`)\n\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {\n\t\t`DBFind(` + name + `, src).Limit(2)`}}, &retCont))\n\n\tif strings.Contains(RawToString(retCont.Tree), `active`) {\n\t\tt.Errorf(`wrong tree %s`, RawToString(retCont.Tree))\n\t\treturn\n\t}\n\n\tassert.NoError(t, postTx(`GetOK`+name, &url.Values{}))\n\n\tassert.NoError(t, postTx(`EditColumn`, &url.Values{`TableName`: {name}, `Name`: {`active`},\n\t\t\"UpdatePerm\": {\"true\"}, \"ReadPerm\": {\"true\" /*\"ContractConditions(\\\"MainCondition\\\")\"*/},\n\t}))\n\tvar ret listResult\n\tassert.NoError(t, sendGet(`list/`+name, nil, &ret))\n\n\tassert.NoError(t, postTx(`Get`+name, &url.Values{}))\n\n\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {\n\t\t`DBFind(` + name + `, src).Limit(2)`}}, &retCont))\n\tif !strings.Contains(RawToString(retCont.Tree), `Alex 2`) {\n\t\tt.Errorf(`wrong tree %s`, RawToString(retCont.Tree))\n\t\treturn\n\t}\n\n\tform = url.Values{\"Name\": {name}, \"InsertPerm\": {`ContractConditions(\"MainCondition\")`},\n\t\t\"UpdatePerm\": {\"true\"}, \"ReadPerm\": {`false`}, \"NewColumnPerm\": {`true`}}\n\tassert.NoError(t, postTx(`EditTable`, &form))\n\tassert.EqualError(t, postTx(`GetOK`+name, &url.Values{}), `{\"type\":\"panic\",\"error\":\"Access denied\"}`)\n\n\tassert.EqualError(t, sendGet(`list/`+name, nil, &ret), `400 {\"error\":\"E_SERVER\",\"msg\":\"Access denied\"}`)\n\n\tform = url.Values{\"Name\": {name}, \"InsertPerm\": {`ContractConditions(\"MainCondition\")`},\n\t\t\"UpdatePerm\": {\"true\"}, \"FilterPerm\": {`ReadFilter` + name + `()`},\n\t\t\"NewColumnPerm\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`EditTable`, &form))\n\n\tvar tableInfo tableResult\n\tassert.NoError(t, sendGet(`table/`+name, nil, &tableInfo))\n\tassert.Equal(t, `ReadFilter`+name+`()`, tableInfo.Filter)\n\n\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {\n\t\t`DBFind(` + name + `, src).Limit(2)`}}, &retCont))\n\tif !strings.Contains(RawToString(retCont.Tree), `No name`) {\n\t\tt.Errorf(`wrong tree %s`, RawToString(retCont.Tree))\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "packages/api/request.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\ntype Connect struct {\n\tAuth       string\n\tRoot       string\n\tPrivateKey []byte\n\tPublicKey  string\n}\n\ntype WaitResult struct {\n\tBlockID int64\n\tMsg     string\n}\n\nfunc SendRawRequest(rtype, url, auth string, form *url.Values) ([]byte, error) {\n\tclient := &http.Client{}\n\tvar ioform io.Reader\n\tif form != nil {\n\t\tioform = strings.NewReader(form.Encode())\n\t}\n\treq, err := http.NewRequest(rtype, url, ioform)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\tif len(auth) > 0 {\n\t\treq.Header.Set(\"Authorization\", jwtPrefix+auth)\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer resp.Body.Close()\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(`%d %s`, resp.StatusCode, strings.TrimSpace(string(data)))\n\t}\n\n\treturn data, nil\n}\n\nfunc SendRequest(rtype, url, auth string, form *url.Values, v any) error {\n\tdata, err := SendRawRequest(rtype, url, auth, form)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn json.Unmarshal(data, v)\n}\n\nfunc (connect *Connect) SendGet(url string, form *url.Values, v any) error {\n\treturn SendRequest(\"GET\", connect.Root+url, connect.Auth, form, v)\n}\n\nfunc (connect *Connect) SendPost(url string, form *url.Values, v any) error {\n\treturn SendRequest(\"POST\", connect.Root+url, connect.Auth, form, v)\n}\n\nfunc (connect *Connect) SendMultipart(url string, files map[string][]byte, v any) error {\n\tbody := new(bytes.Buffer)\n\twriter := multipart.NewWriter(body)\n\n\tfor key, data := range files {\n\t\tpart, err := writer.CreateFormFile(key, key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := part.Write(data); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := writer.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treq, err := http.NewRequest(\"POST\", connect.Root+url, body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n\tif len(connect.Auth) > 0 {\n\t\treq.Header.Set(\"Authorization\", jwtPrefix+connect.Auth)\n\t}\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(`%d %s`, resp.StatusCode, strings.TrimSpace(string(data)))\n\t}\n\n\treturn json.Unmarshal(data, &v)\n}\n\nfunc (connect *Connect) WaitTx(hash string) (int64, error) {\n\tdata, err := json.Marshal(&txstatusRequest{\n\t\tHashes: []string{hash},\n\t})\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tfor i := 0; i < 15; i++ {\n\t\tvar multiRet multiTxStatusResult\n\t\terr := connect.SendPost(`txstatus`, &url.Values{\n\t\t\t\"data\": {string(data)},\n\t\t}, &multiRet)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tret := multiRet.Results[hash]\n\n\t\tif len(ret.BlockID) > 0 {\n\t\t\treturn converter.StrToInt64(ret.BlockID), fmt.Errorf(ret.Result)\n\t\t}\n\t\tif ret.Message != nil {\n\t\t\terrtext, err := json.Marshal(ret.Message)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\treturn 0, errors.New(string(errtext))\n\t\t}\n\t\ttime.Sleep(time.Second)\n\t}\n\treturn 0, fmt.Errorf(`TxStatus timeout`)\n}\n\nfunc (connect *Connect) WaitTxList(hashes []string) (map[string]WaitResult, error) {\n\tdata, err := json.Marshal(&txstatusRequest{\n\t\tHashes: hashes,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar multiRet multiTxStatusResult\n\terr = connect.SendPost(`txstatus`, &url.Values{\n\t\t\"data\": {string(data)},\n\t}, &multiRet)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twaitResults := map[string]WaitResult{}\n\tfor key, ret := range multiRet.Results {\n\t\tif len(ret.BlockID) > 0 {\n\t\t\twaitResults[key] = WaitResult{\n\t\t\t\tBlockID: converter.StrToInt64(ret.BlockID),\n\t\t\t\tMsg:     ret.Result,\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif ret.Message != nil {\n\t\t\tvar msg string\n\t\t\terrtext, err := json.Marshal(ret.Message)\n\t\t\tif err != nil {\n\t\t\t\tmsg = err.Error()\n\t\t\t} else {\n\t\t\t\tmsg = string(errtext)\n\t\t\t}\n\t\t\twaitResults[key] = WaitResult{\n\t\t\t\tMsg: msg,\n\t\t\t}\n\t\t}\n\t}\n\treturn waitResults, nil\n}\n\nfunc (connect *Connect) PostTxResult(name string, form *url.Values) (id int64, msg string, err error) {\n\tvar contract getContractResult\n\tif err = connect.SendGet(\"contract/\"+name, nil, &contract); err != nil {\n\t\treturn\n\t}\n\tparams := make(map[string]any)\n\tfor _, field := range contract.Fields {\n\t\tname := field.Name\n\t\tvalue := form.Get(name)\n\n\t\tif len(value) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch field.Type {\n\t\tcase \"bool\":\n\t\t\tparams[name], err = strconv.ParseBool(value)\n\t\tcase \"int\", \"address\":\n\t\t\tparams[name], err = strconv.ParseInt(value, 10, 64)\n\t\tcase \"float\":\n\t\t\tparams[name], err = strconv.ParseFloat(value, 64)\n\t\tcase \"array\":\n\t\t\tvar v any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"map\":\n\t\t\tvar v map[string]any\n\t\t\terr = json.Unmarshal([]byte(value), &v)\n\t\t\tparams[name] = v\n\t\tcase \"string\", \"money\":\n\t\t\tparams[name] = value\n\t\t}\n\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Parse param '%s': %s\", name, err)\n\t\t\treturn\n\t\t}\n\t}\n\n\tvar publicKey []byte\n\tif publicKey, err = crypto.PrivateToPublic(connect.PrivateKey); err != nil {\n\t\treturn\n\t}\n\ttxTime := time.Now().Unix()\n\n\tif newTime := form.Get(\"txtime\"); len(newTime) > 0 {\n\t\ttxTime = converter.StrToInt64(newTime)\n\t}\n\n\tdata, txhash, err := transaction.NewTransactionInProc(types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(contract.ID),\n\t\t\tEcosystemID: 1,\n\t\t\tTime:        txTime,\n\t\t\tKeyID:       crypto.Address(publicKey),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tParams: params,\n\t}, connect.PrivateKey)\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tret := &sendTxResult{}\n\terr = connect.SendMultipart(\"sendTx\", map[string][]byte{\n\t\tfmt.Sprintf(\"%x\", txhash): data,\n\t}, &ret)\n\tif err != nil {\n\t\treturn\n\t}\n\tif len(form.Get(\"nowait\")) > 0 {\n\t\tmsg = ret.Hashes[\"data\"]\n\t\treturn\n\t}\n\tid, err = connect.WaitTx(ret.Hashes[fmt.Sprintf(\"%x\", txhash)])\n\tif id != 0 && err != nil {\n\t\tmsg = err.Error()\n\t\terr = nil\n\t}\n\n\treturn\n}\n\nfunc (connect *Connect) Login() error {\n\tvar (\n\t\tsign []byte\n\t\tret  getUIDResult\n\t\terr  error\n\t)\n\tif err = connect.SendGet(`getuid`, nil, &ret); err != nil {\n\t\treturn err\n\t}\n\tif len(ret.UID) == 0 {\n\t\treturn nil\n\t}\n\tconnect.Auth = ret.Token\n\tsign, err = crypto.SignString(hex.EncodeToString(connect.PrivateKey), `LOGIN`+ret.NetworkID+ret.UID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tform := url.Values{\"pubkey\": {connect.PublicKey}, \"signature\": {hex.EncodeToString(sign)},\n\t\t`ecosystem`: {`1`}, \"role_id\": {\"0\"}}\n\tvar logret loginResult\n\terr = connect.SendPost(`login`, &form, &logret)\n\tconnect.Auth = logret.Token\n\treturn err\n}\n"
  },
  {
    "path": "packages/api/route.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gorilla/handlers\"\n\t\"github.com/gorilla/mux\"\n)\n\nconst corsMaxAge = 600\n\ntype Router struct {\n\tmain        *mux.Router\n\tapiVersions map[string]*mux.Router\n}\n\nfunc (r Router) GetAPI() *mux.Router {\n\treturn r.main\n}\n\nfunc (r Router) GetAPIVersion(preffix string) *mux.Router {\n\treturn r.apiVersions[preffix]\n}\n\nfunc (r Router) NewVersion(preffix string) *mux.Router {\n\tapi := r.main.PathPrefix(preffix).Subrouter()\n\tr.apiVersions[preffix] = api\n\treturn api\n}\n\n// Route sets routing pathes\nfunc (m Mode) SetCommonRoutes(r Router) {\n\tNoneMiddlewareRoutes(r.NewVersion(\"/api/v2\"), m)\n\n\tapi := r.NewVersion(\"/api/v2\")\n\tapi.Use(nodeStateMiddleware, tokenMiddleware, m.clientMiddleware)\n\n\tSetOtherCommonRoutes(api, m)\n\tapi.HandleFunc(\"/data/{id}/data/{hash}\", getBinaryHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/data/{table}/{id}/{column}/{hash}\", getDataHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/avatar/{ecosystem}/{account}\", getAvatarHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/auth/status\", getAuthStatus).Methods(\"GET\")\n\n\tapi.HandleFunc(\"/contract/{name}\", authRequire(getContractInfoHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/contracts\", authRequire(getContractsHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/getuid\", getUIDHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/keyinfo/{wallet}\", m.getKeyInfoHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/list/{name}\", authRequire(getListHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/network\", getNetworkHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/sections\", authRequire(getSectionsHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/row/{name}/{id}\", authRequire(getRowHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/row/{name}/{column}/{id}\", authRequire(getRowHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/interface/page/{name}\", authRequire(getPageRowHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/interface/menu/{name}\", authRequire(getMenuRowHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/interface/snippet/{name}\", authRequire(getSnippetRowHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/table/{name}\", authRequire(getTableHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/tables\", authRequire(getTablesHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/config/{option}\", getConfigOptionHandler).Methods(\"GET\")\n\n\tapi.HandleFunc(\"/page/validators_count/{name}\", getPageValidatorsCountHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/content/source/{name}\", authRequire(getSourceHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/content/page/{name}\", authRequire(getPageHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/content/hash/{name}\", getPageHashHandler).Methods(\"POST\")\n\tapi.HandleFunc(\"/content/menu/{name}\", authRequire(getMenuHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/content\", jsonContentHandler).Methods(\"POST\")\n\tapi.HandleFunc(\"/login\", m.loginHandler).Methods(\"POST\")\n\tapi.HandleFunc(\"/sendTx\", authRequire(m.sendTxHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/node/{name}\", nodeContractHandler).Methods(\"POST\")\n\tapi.HandleFunc(\"/txstatus\", authRequire(getTxStatusHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/metrics/blocks\", blocksCountHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/metrics/transactions\", txCountHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/metrics/ecosystems\", ecosysCountHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/metrics/keys\", keysCountHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/metrics/mem\", memStatHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/metrics/ban\", banStatHandler).Methods(\"GET\")\n\n}\n\nfunc (m Mode) SetBlockchainRoutes(r Router) {\n\tapi := r.GetAPIVersion(\"/api/v2\")\n\tsetOtherBlockChainRoutes(api, m)\n\tapi.HandleFunc(\"/metrics/honornodes\", honorNodesCountHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/txinfo/{hash}\", getTxInfoHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/txinfomultiple\", getTxInfoMultiHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/appparam/{appID}/{name}\", authRequire(m.GetAppParamHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/appparams/{appID}\", authRequire(m.getAppParamsHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/appcontent/{appID}\", authRequire(m.getAppContentHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/history/{name}/{id}\", authRequire(getHistoryHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/balance/{wallet}\", m.getBalanceHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/block/{id}\", getBlockInfoHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/maxblockid\", getMaxBlockHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/blocks\", getBlocksTxInfoHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/detailed_blocks\", getBlocksDetailedInfoHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/ecosystemparams\", authRequire(m.getEcosystemParamsHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/systemparams\", authRequire(getPlatformParamsHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/ecosystemparam/{name}\", authRequire(m.getEcosystemParamHandler)).Methods(\"GET\")\n\tapi.HandleFunc(\"/ecosystemname\", getEcosystemNameHandler).Methods(\"GET\")\n}\n\nfunc NoneMiddlewareRoutes(api *mux.Router, m Mode) {\n\tapi.HandleFunc(\"/version\", getVersionHandler).Methods(\"GET\")\n}\n\nfunc SetOtherCommonRoutes(api *mux.Router, m Mode) {\n\tapi.HandleFunc(\"/member/{ecosystem}/{account}\", getMemberHandler).Methods(\"GET\")\n\tapi.HandleFunc(\"/listWhere/{name}\", authRequire(getListWhereHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/nodelistWhere/{name}\", authRequire(getListWhereHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/sumWhere/{name}\", authRequire(getsumWhereHandler)).Methods(\"POST\")\n\tapi.HandleFunc(\"/metrics/blockper/{node}/{mode}\", blocksCountByNodeHandler).Methods(\"GET\")\n}\n\nfunc setOtherBlockChainRoutes(api *mux.Router, m Mode) {\n\tapi.HandleFunc(\"/tx_record/{hashes}\", getTxRecord).Methods(\"GET\")\n}\n\nfunc (m Mode) SetSubNodeRoutes(r Router) {}\n\nfunc NewRouter(m Mode) Router {\n\tr := mux.NewRouter()\n\tr.StrictSlash(true)\n\tr.Use(loggerMiddleware, recoverMiddleware, statsdMiddleware)\n\n\tapi := Router{\n\t\tmain:        r,\n\t\tapiVersions: make(map[string]*mux.Router),\n\t}\n\tm.SetCommonRoutes(api)\n\treturn api\n}\n\nfunc WithCors(h http.Handler) http.Handler {\n\treturn handlers.CORS(\n\t\thandlers.AllowedOrigins([]string{\"*\"}),\n\t\thandlers.AllowedMethods([]string{\"GET\", \"HEAD\", \"POST\"}),\n\t\thandlers.AllowedHeaders([]string{\"Authorization\", \"Content-Type\", \"X-Requested-With\"}),\n\t\thandlers.MaxAge(corsMaxAge),\n\t)(h)\n}\n"
  },
  {
    "path": "packages/api/row.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype rowResult struct {\n\tValue map[string]string `json:\"value\"`\n}\n\ntype rowForm struct {\n\tColumns string `schema:\"columns\"`\n}\n\nfunc (f *rowForm) Validate(r *http.Request) error {\n\tif len(f.Columns) > 0 {\n\t\tcolumns := strings.Split(f.Columns, \",\")\n\t\tlist := make([]string, len(columns))\n\t\tfor k, column := range columns {\n\t\t\tlist[k] = converter.Sanitize(column, `->`)\n\t\t}\n\t\tf.Columns = strings.Join(list, \",\")\n\t}\n\treturn nil\n}\n\nfunc getRowHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &rowForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tq := sqldb.GetDB(nil).Limit(1)\n\n\tvar (\n\t\terr   error\n\t\ttable string\n\t)\n\ttable, form.Columns, err = checkAccess(params[\"name\"], form.Columns, client)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tcol := `id`\n\tif len(params[\"column\"]) > 0 {\n\t\tcol = converter.Sanitize(params[\"column\"], `-`)\n\t}\n\tif converter.FirstEcosystemTables[params[\"name\"]] {\n\t\tq = q.Table(table).Where(col+\" = ? and ecosystem = ?\", params[\"id\"], client.EcosystemID)\n\t} else {\n\t\tq = q.Table(table).Where(col+\" = ?\", params[\"id\"])\n\t}\n\n\tif len(form.Columns) > 0 {\n\t\tq = q.Select(form.Columns)\n\t}\n\n\trows, err := q.Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\terrorResponse(w, errQuery)\n\t\treturn\n\t}\n\n\tresult, err := sqldb.GetResult(rows)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif len(result) == 0 {\n\t\terrorResponse(w, errNotFound)\n\t\treturn\n\t}\n\n\tjsonResponse(w, &rowResult{\n\t\tValue: result[0],\n\t})\n}\n"
  },
  {
    "path": "packages/api/sections.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/language\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst defaultSectionsLimit = 100\n\ntype sectionsForm struct {\n\tpaginatorForm\n\tLang string `schema:\"lang\"`\n}\n\nfunc (f *sectionsForm) Validate(r *http.Request) error {\n\tif err := f.paginatorForm.Validate(r); err != nil {\n\t\treturn err\n\t}\n\n\tif len(f.Lang) == 0 {\n\t\tf.Lang = r.Header.Get(\"Accept-Language\")\n\t}\n\n\treturn nil\n}\n\nfunc getSectionsHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &sectionsForm{}\n\tform.defaultLimit = defaultSectionsLimit\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\ttable := \"1_sections\"\n\tq := sqldb.GetDB(nil).Table(table).Where(\"ecosystem = ? AND status > 0\", client.EcosystemID).Order(\"id ASC\")\n\n\tresult := new(listResult)\n\terr := q.Count(&result.Count).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting table records count\")\n\t\terrorResponse(w, errTableNotFound.Errorf(table))\n\t\treturn\n\t}\n\n\trows, err := q.Offset(form.Offset).Limit(form.Limit).Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tresult.List, err = sqldb.GetResult(rows)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tvar sections []map[string]string\n\tfor _, item := range result.List {\n\t\tvar roles []int64\n\t\tif err := json.Unmarshal([]byte(item[\"roles_access\"]), &roles); err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tif len(roles) > 0 {\n\t\t\tvar added bool\n\t\t\tfor _, v := range roles {\n\t\t\t\tif v == client.RoleID {\n\t\t\t\t\tadded = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !added {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif item[\"status\"] == consts.StatusMainPage {\n\t\t\troles := &sqldb.Role{}\n\t\t\troles.SetTablePrefix(1)\n\t\t\trole, err := roles.Get(nil, client.RoleID)\n\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Debug(\"Getting role by id\")\n\t\t\t\terrorResponse(w, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif role == true && roles.DefaultPage != \"\" {\n\t\t\t\titem[\"default_page\"] = roles.DefaultPage\n\t\t\t}\n\t\t}\n\n\t\titem[\"title\"] = language.LangMacro(item[\"title\"], int(client.EcosystemID), form.Lang)\n\t\tsections = append(sections, item)\n\t}\n\tresult.List = sections\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/send_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype sendTxResult struct {\n\tHashes map[string]string `json:\"hashes\"`\n}\n\nfunc getTxData(r *http.Request, key string) ([]byte, error) {\n\tlogger := getLogger(r)\n\n\tfile, _, err := r.FormFile(key)\n\tif err != nil {\n\t\tlogger.WithError(err).Error(\"request.FormFile\")\n\t\treturn nil, err\n\t}\n\tdefer file.Close()\n\n\tvar txData []byte\n\tif txData, err = io.ReadAll(file); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading multipart file\")\n\t\treturn nil, err\n\t}\n\n\treturn txData, nil\n}\n\nfunc (m Mode) sendTxHandler(w http.ResponseWriter, r *http.Request) {\n\tclient := getClient(r)\n\n\tif transaction.IsKeyBanned(client.KeyID) {\n\t\terrorResponse(w, errBanned.Errorf(client.KeyID, transaction.BannedTill(client.KeyID)))\n\t\treturn\n\t}\n\n\terr := r.ParseMultipartForm(multipartBuf)\n\tif err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\tresult := &sendTxResult{Hashes: make(map[string]string)}\n\tvar mtx = make(map[string][]byte, 0)\n\tfor key := range r.MultipartForm.File {\n\t\ttxData, err := getTxData(r, key)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tmtx[key] = txData\n\t}\n\n\tfor key := range r.Form {\n\t\ttxData, err := hex.DecodeString(r.FormValue(key))\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tmtx[key] = txData\n\t}\n\n\thash, err := txHandlerBatches(r, m, mtx)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\tfor _, key := range hash {\n\t\tresult.Hashes[key] = key\n\t}\n\tjsonResponse(w, result)\n}\n\nfunc txHandlerBatches(r *http.Request, m Mode, mtx map[string][]byte) ([]string, error) {\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\tvar txData [][]byte\n\tfor _, datum := range mtx {\n\t\ttxData = append(txData, datum)\n\t}\n\tif int64(len(txData)) > syspar.GetMaxTxSize() {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"max_size\": syspar.GetMaxTxSize(), \"size\": len(txData)}).Error(\"transaction size exceeds max size\")\n\t\ttransaction.BadTxForBan(client.KeyID)\n\t\treturn nil, errLimitTxSize.Errorf(len(txData))\n\t}\n\n\thash, err := m.ClientTxProcessor.ProcessClientTxBatches(txData, client.KeyID, logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn hash, nil\n}\n"
  },
  {
    "path": "packages/api/smart_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/shopspring/decimal\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype smartParams struct {\n\tParams  map[string]string\n\tResults map[string]string\n}\n\ntype smartContract struct {\n\tName   string\n\tValue  string\n\tParams []smartParams\n}\n\nfunc TestUpperName(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\trnd := crypto.RandSeq(4)\n\tform := url.Values{\"Name\": {\"testTable\" + rnd}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"num\",\"type\":\"text\",   \"conditions\":\"true\"},\n\t{\"name\":\"text\", \"type\":\"text\",\"conditions\":\"true\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\terr := postTx(`NewTable`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Value`: {`contract AddRow` + rnd + ` {\n\t\tdata {\n\t\t}\n\t\tconditions {\n\t\t}\n\t\taction {\n\t\t   DBInsert(\"testTable` + rnd + `\", {num: \"fgdgf\", text: \"124234\"}) \n\t\t}\n\t}`}, \"ApplicationId\": {\"1\"}, `Conditions`: {`true`}}\n\tif err := postTx(`NewContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif err := postTx(`AddRow`+rnd, &url.Values{}); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestSmartFields(t *testing.T) {\n\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar cntResult getContractResult\n\terr := sendGet(`contract/MainCondition`, nil, &cntResult)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(cntResult.Fields) != 0 {\n\t\tt.Error(`MainCondition fields must be empty`)\n\t\treturn\n\t}\n\tif cntResult.Name != `@1MainCondition` {\n\t\tt.Errorf(`MainCondition name is wrong: %s`, cntResult.Name)\n\t\treturn\n\t}\n\tif err := postTx(`MainCondition`, &url.Values{}); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestMoneyTransfer(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tform := url.Values{`Amount`: {`53330000`}, `Recipient`: {`0005-2070-2000-0006-0200`}}\n\tif err := postTx(`MoneyTransfer`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Amount`: {`2440000`}, `Recipient`: {`1109-7770-3360-6764-7059`}, `Comment`: {`Test`}}\n\tif err := postTx(`MoneyTransfer`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{`Amount`: {`53330000`}, `Recipient`: {`0005207000`}}\n\tif err := postTx(`MoneyTransfer`, &form); cutErr(err) != `{\"type\":\"error\",\"error\":\"Recipient 0005207000 is invalid\"}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tsize := 1000000\n\tbig := make([]byte, size)\n\trand.Seed(time.Now().UnixNano())\n\tfor i := 0; i < size; i++ {\n\t\tbig[i] = '0' + byte(rand.Intn(10))\n\t}\n\tform = url.Values{`Amount`: {string(big)}, `Recipient`: {`0005-2070-2000-0006-0200`}}\n\tif err := postTx(`MoneyTransfer`, &form); err.Error() != `400 {\"error\": \"E_LIMITFORSIGN\", \"msg\": \"Length of forsign is too big (1000106)\" , \"params\": [\"1000106\"]}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestRoleAccess(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`page`)\n\tmenu := `government`\n\tvalue := `P(test,test paragraph)`\n\n\tform := url.Values{\"Name\": {name}, \"Value\": {value}, \"Menu\": {menu}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`RoleAccess(10,1)`}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\n\tvar ret listResult\n\tassert.NoError(t, sendGet(`list/pages`, nil, &ret))\n\tid := strconv.FormatInt(ret.Count, 10)\n\tform = url.Values{\"Id\": {id}, \"Value\": {\"Div(){Ooops}\"}, \"Conditions\": {`RoleAccess(65)`}}\n\tassert.NoError(t, postTx(`EditPage`, &form))\n\tform = url.Values{\"Id\": {id}, \"Value\": {\"Div(){Update}\"}}\n\tassert.EqualError(t, postTx(`EditPage`, &form), `{\"type\":\"panic\",\"error\":\"Access denied\"}`)\n}\n\nfunc TestDBFind(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\tname := randName(`tbl`)\n\tform := url.Values{\"Name\": {name}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"txt\",\"type\":\"varchar\", \n\t\t\"conditions\":\"true\"},\n\t  {\"name\":\"Name\", \"type\":\"varchar\",\"index\": \"0\", \"conditions\":\"{\\\"read\\\":\\\"true\\\",\\\"update\\\":\\\"true\\\"}\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\tform = url.Values{`Value`: {`contract sub` + name + ` {\n\t\taction {\n\t\t\tDBInsert(\"` + name + `\", {txt:\"ok\", name: \"thisis\"})\n\t\t\tDBInsert(\"` + name + `\", {txt:\"test\", name: \"test\"})\n\t\t\t$result = DBFind(\"` + name + `\").Columns(\"name\").Where({txt:\"test\"}).One(\"name\")\n\t\t}\n\t}`}, `Conditions`: {`true`}, \"ApplicationId\": {\"1\"}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\t_, ret, err := postTxResult(`sub`+name, &url.Values{})\n\tassert.Equal(t, `heading`, ret)\n\tvar retPage contentResult\n\tvalue := `DBFind(` + name + `, src).Columns(name).Where({txt:test})`\n\tform = url.Values{\"Name\": {name}, \"Value\": {value}, \"ApplicationId\": {`1`},\n\t\t\"Menu\": {`default_menu`}, \"Conditions\": {\"ContractConditions(`MainCondition`)\"}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\tassert.NoError(t, sendPost(`content/page/`+name, &url.Values{}, &retPage))\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif RawToString(retPage.Tree) != `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"name\",\"id\"],\"data\":[[\"test\",\"2\"]],\"name\":\"`+name+`\",\"source\":\"src\",\"types\":[\"text\",\"text\"],\"where\":\"{txt:test}\"}}]` {\n\t\tt.Error(fmt.Errorf(`wrong tree %s`, RawToString(retPage.Tree)))\n\t\treturn\n\t}\n}\nfunc TestPage(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`page`)\n\tmenuname := randName(`menu`)\n\tmenu := `government`\n\tvalue := `P(test,test paragraph)`\n\n\tform := url.Values{\"Name\": {name}, \"Value\": {`Param Value`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewParameter`, &form))\n\n\terr := postTx(`NewParameter`, &form)\n\tassert.Equal(t, fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Parameter %s already exists\"}`, name), cutErr(err))\n\n\tform = url.Values{\"Name\": {menuname}, \"Value\": {`first\n\t\t\tsecond\n\t\t\tthird`}, \"Title\": {`My Menu`},\n\t\t\"Conditions\": {`true`}}\n\tassert.NoError(t, postTx(`NewMenu`, &form))\n\n\terr = postTx(`NewMenu`, &form)\n\tassert.Equal(t, fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Menu %s already exists\"}`, menuname), cutErr(err))\n\n\tform = url.Values{\"Id\": {`7123`}, \"Value\": {`New Param Value`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\terr = postTx(`EditParameter`, &form)\n\tassert.Equal(t, `{\"type\":\"panic\",\"error\":\"Item 7123 has not been found\"}`, cutErr(err))\n\n\tform = url.Values{\"Id\": {`16`}, \"Value\": {`Changed Param Value`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`EditParameter`, &form))\n\n\tname = randName(`page`)\n\tform = url.Values{\"Name\": {name}, \"Value\": {value}, \"ApplicationId\": {`1`},\n\t\t\"Menu\": {menu}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\n\terr = postTx(`NewPage`, &form)\n\tassert.Equal(t, fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Page %s already exists\"}`, name), cutErr(err))\n\terr = postTx(`NewPage`, &form)\n\tif cutErr(err) != fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Page %s already exists\"}`, name) {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{\"Name\": {`app` + name}, \"Value\": {value}, \"ValidateCount\": {\"2\"},\n\t\t\"ValidateMode\": {\"1\"}, \"ApplicationId\": {`1`},\n\t\t\"Menu\": {menu}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\terr = postTx(`NewPage`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tvar ret listResult\n\terr = sendGet(`list/pages`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tid := strconv.FormatInt(ret.Count, 10)\n\tform = url.Values{\"Id\": {id}, \"ValidateCount\": {\"2\"}, \"ValidateMode\": {\"1\"}}\n\terr = postTx(`EditPage`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar row rowResult\n\terr = sendGet(`row/pages/`+id, nil, &row)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tif row.Value[\"validate_mode\"] != `1` {\n\t\tt.Errorf(`wrong validate value %s`, row.Value[\"validate_mode\"])\n\t\treturn\n\t}\n\n\tform = url.Values{\"Id\": {id}, \"Value\": {value}, \"ValidateCount\": {\"1\"},\n\t\t\"ValidateMode\": {\"0\"}}\n\terr = postTx(`EditPage`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = sendGet(`row/pages/`+id, nil, &row)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif row.Value[\"validate_mode\"] != `0` {\n\t\tt.Errorf(`wrong validate value %s`, row.Value[\"validate_mode\"])\n\t\treturn\n\t}\n\n\tform = url.Values{\"Id\": {id}, \"Value\": {value}, \"ValidateCount\": {\"1\"},\n\t\t\"ValidateMode\": {\"0\"}}\n\terr = postTx(`EditPage`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = sendGet(`row/pages/`+id, nil, &row)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif row.Value[\"validate_mode\"] != `0` {\n\t\tt.Errorf(`wrong validate value %s`, row.Value[\"validate_mode\"])\n\t\treturn\n\t}\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {value}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewSnippet`, &form))\n\n\terr = postTx(`NewSnippet`, &form)\n\tassert.EqualError(t, err, fmt.Sprintf(`{\"type\":\"warning\",\"error\":\"Block %s already exists\"}`, name))\n\n\tform = url.Values{\"Id\": {`1`}, \"Name\": {name}, \"Value\": {value},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`EditSnippet`, &form))\n\n\tform = url.Values{\"Id\": {`1`}, \"Value\": {value + `Span(Test)`},\n\t\t\"Menu\": {menu}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`EditPage`, &form))\n\n\tform = url.Values{\"Id\": {`1112`}, \"Value\": {value + `Span(Test)`},\n\t\t\"Menu\": {menu}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\terr = postTx(`EditPage`, &form)\n\tassert.Equal(t, `{\"type\":\"panic\",\"error\":\"Item 1112 has not been found\"}`, cutErr(err))\n\n\tform = url.Values{\"Id\": {`1`}, \"Value\": {`Span(Append)`}}\n\tassert.NoError(t, postTx(`AppendPage`, &form))\n}\n\nfunc TestNewTableOnly(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := \"MMy_s_test_table\"\n\tform := url.Values{\"Name\": {name}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \n\t\t\"conditions\":\"true\"},\n\t  {\"name\":\"Name\", \"type\":\"varchar\",\"index\": \"0\", \"conditions\":\"{\\\"read\\\":\\\"true\\\",\\\"update\\\":\\\"true\\\"}\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\trequire.NoError(t, postTx(`NewTable`, &form))\n\n\tvar ret tableResult\n\trequire.NoError(t, sendGet(`table/`+name, nil, &ret))\n\tfmt.Printf(\"%+v\\n\", ret)\n}\n\nfunc TestUpperTable(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`Tab_`)\n\tform := url.Values{\"Name\": {name}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \n\t\t\"conditions\":\"true\"},\n\t  {\"name\":\"Name\", \"type\":\"varchar\",\"index\": \"0\", \"conditions\":\"{\\\"read\\\":\\\"true\\\",\\\"update\\\":\\\"true\\\"}\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tform = url.Values{\"TableName\": {name}, \"Name\": {`newCol`},\n\t\t\"Type\": {\"varchar\"}, \"Index\": {\"0\"}, \"UpdatePerm\": {\"true\"}, \"ReadPerm\": {\"true\"}}\n\tassert.NoError(t, postTx(`NewColumn`, &form))\n\tform = url.Values{\"TableName\": {name}, \"Name\": {`newCol`},\n\t\t\"UpdatePerm\": {\"true\"}, \"ReadPerm\": {\"true\"}}\n\tassert.NoError(t, postTx(`EditColumn`, &form))\n}\n\nfunc TestNewTable(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`tbl`)\n\tform := url.Values{\"Name\": {`1_` + name}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \n\t\t\"conditions\":\"true\"},\n\t  {\"name\":\"Name\", \"type\":\"varchar\",\"index\": \"0\", \"conditions\":\"{\\\"read\\\":\\\"true\\\",\\\"update\\\":\\\"true\\\"}\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tform = url.Values{\"TableName\": {`1_` + name}, \"Name\": {`newCol`},\n\t\t\"Type\": {\"varchar\"}, \"Index\": {\"0\"}, \"Permissions\": {\"true\"}}\n\tassert.NoError(t, postTx(`NewColumn`, &form))\n\n\tform = url.Values{`Value`: {`contract sub` + name + ` {\n\t\taction {\n\t\t\tDBInsert(\"1_` + name + `\", {\"name\": \"ok\"})\n\t\t\tDBUpdate(\"1_` + name + `\", 1, {\"name\": \"test value\"} )\n\t\t\t$result = DBFind(\"1_` + name + `\").Columns(\"name\").WhereId(1).One(\"name\")\n\t\t}\n\t}`}, `Conditions`: {`true`}, \"ApplicationId\": {\"1\"}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\t_, msg, err := postTxResult(`sub`+name, &url.Values{})\n\tassert.NoError(t, err)\n\tassert.Equal(t, msg, \"test value\")\n\n\tform = url.Values{\"Name\": {name}, \"ApplicationId\": {\"1\"}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \"index\": \"1\", \n\t  \"conditions\":\"true\"},\n\t{\"name\":\"Amount\", \"type\":\"number\",\"index\": \"0\", \"conditions\":\"true\"},\n\t{\"name\":\"Doc\", \"type\":\"json\",\"index\": \"0\", \"conditions\":\"true\"},\t\n\t{\"name\":\"Active\", \"type\":\"character\",\"index\": \"0\", \"conditions\":\"true\"}]`},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tassert.EqualError(t, postTx(`NewTable`, &form), fmt.Sprintf(`{\"type\":\"panic\",\"error\":\"table %s exists\"}`, name))\n\n\tform = url.Values{\"Name\": {name},\n\t\t\"Permissions\": {`{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\t\"update\" : \"true\", \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}`}}\n\tassert.NoError(t, postTx(`EditTable`, &form))\n\n\tform = url.Values{\"TableName\": {name}, \"Name\": {`newDoc`},\n\t\t\"Type\": {\"json\"}, \"Index\": {\"0\"}, \"Permissions\": {\"true\"}}\n\tassert.NoError(t, postTx(`NewColumn`, &form))\n\n\tform = url.Values{\"TableName\": {name}, \"Name\": {`newCol`},\n\t\t\"Type\": {\"varchar\"}, \"Index\": {\"0\"}, \"Permissions\": {\"true\"}}\n\tassert.NoError(t, postTx(`NewColumn`, &form))\n\n\terr = postTx(`NewColumn`, &form)\n\tif err.Error() != `{\"type\":\"panic\",\"error\":\"column newcol exists\"}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{\"TableName\": {name}, \"Name\": {`newCol`},\n\t\t\"Permissions\": {\"ContractConditions(\\\"MainCondition\\\")\"}}\n\tassert.NoError(t, postTx(`EditColumn`, &form))\n\n\tupname := strings.ToUpper(name)\n\tform = url.Values{\"TableName\": {upname}, \"Name\": {`UPCol`},\n\t\t\"Type\": {\"varchar\"}, \"Index\": {\"0\"}, \"Permissions\": {\"true\"}}\n\tassert.NoError(t, postTx(`NewColumn`, &form))\n\n\tform = url.Values{\"TableName\": {upname}, \"Name\": {`upCOL`},\n\t\t\"Permissions\": {\"ContractConditions(\\\"MainCondition\\\")\"}}\n\tassert.NoError(t, postTx(`EditColumn`, &form))\n\n\tform = url.Values{\"Name\": {upname},\n\t\t\"Permissions\": {`{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t\t\t\"update\" : \"true\", \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}`}}\n\tassert.NoError(t, postTx(`EditTable`, &form))\n\n\tvar ret tablesResult\n\tassert.NoError(t, sendGet(`tables`, nil, &ret))\n}\n\ntype invalidPar struct {\n\tName  string\n\tValue string\n}\n\nfunc TestUpdatePlatformParam(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tform := url.Values{\"Name\": {`max_columns`}, \"Value\": {`49`}}\n\tassert.NoError(t, postTx(`UpdatePlatformParam`, &form))\n\n\tvar sysList paramsResult\n\tassert.NoError(t, sendGet(`systemparams?names=max_columns`, nil, &sysList))\n\tassert.Len(t, sysList.List, 1)\n\tassert.Equal(t, \"49\", sysList.List[0].Value)\n\n\tname := randName(`test`)\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\taction { \n\t\t\tvar costlen int\n\t\t\tcostlen = SysParamInt(\"price_exec_len\") + 1\n\t\t\tUpdatePlatformParam(\"Name,Value\",\"max_columns\",\"51\")\n\t\t\tDBUpdatePlatformParam(\"price_exec_len\", Str(costlen), \"true\" )\n\t\t\tif SysParamInt(\"price_exec_len\") != costlen {\n\t\t\t\terror \"Incorrect updated value\"\n\t\t\t}\n\t\t\tDBUpdatePlatformParam(\"max_indexes\", \"4\", \"false\" )\n\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\terr := postTx(name, &form)\n\tif err != nil {\n\t\tassert.EqualError(t, err, `{\"type\":\"panic\",\"error\":\"Access denied\"}`)\n\t}\n\n\tassert.NoError(t, sendGet(`systemparams?names=max_columns,max_indexes`, nil, &sysList))\n\tif len(sysList.List) != 2 || !((sysList.List[0].Value == `51` && sysList.List[1].Value == `4`) ||\n\t\t(sysList.List[0].Value == `4` && sysList.List[1].Value == `51`)) {\n\t\tt.Error(`Wrong max_column or max_indexes value`)\n\t\treturn\n\t}\n\terr = postTx(name, &form)\n\tif err == nil || err.Error() != `{\"type\":\"panic\",\"error\":\"Access denied\"}` {\n\t\tt.Error(`incorrect access to system parameter`)\n\t\treturn\n\t}\n\n\tnotvalid := []invalidPar{\n\t\t{`gap_between_blocks`, `100000`},\n\t\t{`rollback_blocks`, `-1`},\n\t\t{`price_create_page`, `-20`},\n\t\t{`max_block_size`, `0`},\n\t\t{`max_fuel_tx`, `20string`},\n\t\t{`fuel_rate`, `string`},\n\t\t{`fuel_rate`, `[test]`},\n\t\t{`fuel_rate`, `[[\"name\", \"100\"]]`},\n\t\t{`taxes_wallet`, `[[\"1\", \"0\"]]`},\n\t\t{`taxes_wallet`, `[{\"1\", \"50\"}]`},\n\t\t{`honor_nodes`, `[[\"\", \"http://127.0.0.1\", \"100\", \"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7\"]]`},\n\t\t{`honor_nodes`, `[[\"127.0.0.1\", \"\", \"100\", \"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\"]]`},\n\t\t{`honor_nodes`, `[[\"127.0.0.1\", \"http://127.0.0.1\", \"0\", \"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\"]]`},\n\t\t{\"honor_nodes\", \"[]\"},\n\t}\n\tfor _, item := range notvalid {\n\t\tassert.Error(t, postTx(`UpdatePlatformParam`, &url.Values{`Name`: {item.Name}, `Value`: {item.Value}}))\n\t\tassert.NoError(t, sendGet(`systemparams?names=`+item.Name, nil, &sysList))\n\t\tassert.Len(t, sysList.List, 1, `have got wrong parameter `+item.Name)\n\n\t\tif len(sysList.List[0].Value) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\terr = postTx(`UpdatePlatformParam`, &url.Values{`Name`: {item.Name}, `Value`: {sysList.List[0].Value}})\n\t\tassert.NoError(t, err, item.Name, sysList.List[0].Value, sysList.List[0])\n\t}\n}\n\nfunc TestUpdateHonorNodesWithEmptyArray(t *testing.T) {\n\trequire.NoErrorf(t, keyLogin(1), \"on login\")\n\n\tbyteNodes := `[{\"tcp_address\":\"127.0.0.1:7078\", \"api_address\":\"https://127.0.0.1:7079\", \"key_id\":\"-3122230976936134914\", \"public_key\":\"d512e7bbaaa8889e2e471d730bbae663bd291a345153ff34d1d9896e36832408eb9f238deca8d410aeb282ff8547ba3f056c5b2a64e2d0b03928e6dd1336e918\"},\n\t{\"tcp_address\":\"127.0.0.1:7080\", \"api_address\":\"https://127.0.0.1:7081\", \"key_id\":\"-3928816940965469512\", \"public_key\":\"9fdf51cd74e3a03fbe776a7122e2f28e3d560467d96a624296656a3a2120653e6347572a50693077cc8b8309ea1ea4a33cb84b9e62874a2d762aca85fad84bf7\"}]`\n\tform := &url.Values{\n\t\t\"Name\":  {\"honor_nodes\"},\n\t\t\"Value\": {string(byteNodes)},\n\t}\n\n\trequire.NoError(t, postTx(`UpdatePlatformParam`, form))\n}\n\n/*\nfunc TestHelper_InsertNodeKey(t *testing.T) {\n\trequire.NoErrorf(t, keyLogin(1), \"on login\")\n\n\tform := url.Values{\n\t\t`Value`: {`contract InsertNodeKey {\n\t\t\tdata {\n\t\t\t\tKeyID string\n\t\t\t\tPubKey string\n\t\t\t}\n\t\t\tconditions {}\n\t\t\taction {\n\t\t\t\tDBInsert(\"keys\", {id: $KeyID, pub: $PubKey,amount: \"100000000000000000000\"})\n\t\t\t}\n\t\t}`},\n\t\t`ApplicationId`: {`1`},\n\t\t`Conditions`:    {`true`},\n\t}\n\tif err := postTx(`NewContract`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tform = url.Values{\n\t\t`KeyID`:  {\"-3928816940965469512\"},\n\t\t`PubKey`: {\"704dfabedb65099a8f05f9e20a2e2f04da2e2b4fc9fd8a5a487278bd1212a020a3b469c4756e6f3fc4f7162373e8da576085fb840a8c666d58085e631be501d6\"},\n\t}\n\n\tif err := postTx(`InsertNodeKey`, &form); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n*/\nfunc TestValidateConditions(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tbaseForm := url.Values{\"Id\": {\"1\"}, \"Value\": {\"Test\"}, \"Conditions\": {\"incorrectConditions\"}}\n\tcontracts := map[string]url.Values{\n\t\t\"EditContract\":  baseForm,\n\t\t\"EditParameter\": baseForm,\n\t\t\"EditMenu\":      baseForm,\n\t\t\"EditPage\":      {\"Id\": {\"1\"}, \"Value\": {\"Test\"}, \"Conditions\": {\"incorrectConditions\"}, \"Menu\": {\"1\"}},\n\t}\n\texpectedErr := `{\"type\":\"panic\",\"error\":\"unknown identifier incorrectConditions\"}`\n\n\tfor contract, form := range contracts {\n\t\terr := postTx(contract, &form)\n\t\tif err.Error() != expectedErr {\n\t\t\tt.Errorf(\"contract %s expected '%s' got '%s'\", contract, expectedErr, err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestPartitialEdit(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`part`)\n\tform := url.Values{\"Name\": {name}, \"Value\": {\"Span(Original text)\"},\n\t\t\"Menu\": {\"original_menu\"}, \"ApplicationId\": {\"1\"}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\n\tvar retList listResult\n\tassert.NoError(t, sendGet(`list/pages`, nil, &retList))\n\n\tidItem := strconv.FormatInt(retList.Count, 10)\n\tvalue := `Span(Temp)`\n\tmenu := `temp_menu`\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\n\t\t\"Id\":    {idItem},\n\t\t\"Value\": {value},\n\t\t\"Menu\":  {menu},\n\t}))\n\n\tvar ret rowResult\n\tassert.NoError(t, sendGet(`row/pages/`+idItem, nil, &ret))\n\tassert.Equal(t, value, ret.Value[\"value\"])\n\tassert.Equal(t, menu, ret.Value[\"menu\"])\n\n\tvalue = `Span(Updated)`\n\tmenu = `default_menu`\n\tconditions := `true`\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\"Id\": {idItem}, \"Value\": {value}}))\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\"Id\": {idItem}, \"Menu\": {menu}}))\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\"Id\": {idItem}, \"Conditions\": {conditions}}))\n\tassert.NoError(t, sendGet(`row/pages/`+idItem, nil, &ret))\n\tassert.Equal(t, value, ret.Value[\"value\"])\n\tassert.Equal(t, menu, ret.Value[\"menu\"])\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`MenuItem(One)`}, \"Title\": {`My Menu`},\n\t\t\"ApplicationId\": {\"1\"}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewMenu`, &form))\n\tassert.NoError(t, sendGet(`list/menu`, nil, &retList))\n\tidItem = strconv.FormatInt(retList.Count, 10)\n\tvalue = `MenuItem(Two)`\n\tassert.NoError(t, postTx(`EditMenu`, &url.Values{\"Id\": {idItem}, \"Value\": {value}}))\n\tassert.NoError(t, postTx(`EditMenu`, &url.Values{\"Id\": {idItem}, \"Conditions\": {conditions}}))\n\tassert.NoError(t, sendGet(`row/menu/`+idItem, nil, &ret))\n\tassert.Equal(t, value, ret.Value[\"value\"])\n\tassert.Equal(t, conditions, ret.Value[\"conditions\"])\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`Span(Snippet)`},\n\t\t\"ApplicationId\": {\"1\"}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewSnippet`, &form))\n\tassert.NoError(t, sendGet(`list/snippets`, nil, &retList))\n\tidItem = strconv.FormatInt(retList.Count, 10)\n\tvalue = `Span(Updated block)`\n\tassert.NoError(t, postTx(`EditSnippet`, &url.Values{\"Id\": {idItem}, \"Value\": {value}}))\n\tassert.NoError(t, postTx(`EditSnippet`, &url.Values{\"Id\": {idItem}, \"Conditions\": {conditions}}))\n\tassert.NoError(t, sendGet(`row/snippets/`+idItem, nil, &ret))\n\tassert.Equal(t, value, ret.Value[\"value\"])\n\tassert.Equal(t, conditions, ret.Value[\"conditions\"])\n}\n\nfunc TestContractEdit(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tname := randName(`part`)\n\tform := url.Values{\"Value\": {`contract ` + name + ` {\n\t\t    action {\n\t\t\t\t$result = \"before\"\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\terr := postTx(`NewContract`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar retList listResult\n\terr = sendGet(`list/contracts`, nil, &retList)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tidItem := strconv.FormatInt(retList.Count, 10)\n\tvalue := `contract ` + name + ` {\n\t\taction {\n\t\t\t$result = \"after\"\n\t\t}\n\t}`\n\tconditions := `true`\n\twallet := \"1231234123412341230\"\n\terr = postTx(`EditContract`, &url.Values{\"Id\": {idItem}, \"Value\": {value}})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = postTx(`EditContract`, &url.Values{\"Id\": {idItem}, \"Conditions\": {conditions},\n\t\t\"WalletId\": {wallet}})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret rowResult\n\terr = sendGet(`row/contracts/`+idItem, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif ret.Value[\"value\"] != value || ret.Value[\"conditions\"] != conditions ||\n\t\tret.Value[\"wallet_id\"] != wallet {\n\t\tt.Errorf(`wrong parameters of contract`)\n\t\treturn\n\t}\n\t_, msg, err := postTxResult(name, &url.Values{})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif msg != \"after\" {\n\t\tt.Errorf(`the wrong result of the contract %s`, msg)\n\t}\n}\n\nfunc TestDelayedContracts(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tform := url.Values{\n\t\t\"Contract\":   {\"UnknownContract\"},\n\t\t\"EveryBlock\": {\"10\"},\n\t\t\"Limit\":      {\"2\"},\n\t\t\"Conditions\": {\"true\"},\n\t}\n\terr := postTx(\"NewDelayedContract\", &form)\n\tassert.EqualError(t, err, `{\"type\":\"error\",\"error\":\"Unknown contract @1UnknownContract\"}`)\n\n\tform.Set(\"Contract\", \"MainCondition\")\n\terr = postTx(\"NewDelayedContract\", &form)\n\tassert.NoError(t, err)\n\n\tform.Set(\"BlockID\", \"1\")\n\terr = postTx(\"NewDelayedContract\", &form)\n\tassert.EqualError(t, err, `{\"type\":\"error\",\"error\":\"The blockID must be greater than the current blockID\"}`)\n\n\tform = url.Values{\n\t\t\"Id\":         {\"1\"},\n\t\t\"Contract\":   {\"MainCondition\"},\n\t\t\"EveryBlock\": {\"10\"},\n\t\t\"Conditions\": {\"true\"},\n\t\t\"Deleted\":    {\"1\"},\n\t}\n\terr = postTx(\"EditDelayedContract\", &form)\n\tassert.NoError(t, err)\n}\n\nfunc TestJSON(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tcontract := randName(\"JSONEncode\")\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + contract + ` {\n\t\t\taction {\n\t\t\t\tvar a array, m map\n\t\t\t\tm[\"k1\"] = 1\n\t\t\t\tm[\"k2\"] = 2\n\t\t\t\ta[0] = m\n\t\t\t\ta[1] = m\n\n\t\t\t\tinfo JSONEncode(a)\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"},\n\t\t\"Conditions\": {\"true\"},\n\t}))\n\tassert.EqualError(t, postTx(contract, &url.Values{}), `{\"type\":\"info\",\"error\":\"[{\\\"k1\\\":1,\\\"k2\\\":2},{\\\"k1\\\":1,\\\"k2\\\":2}]\"}`)\n\n\tcontract = randName(\"JSONDecode\")\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + contract + ` {\n\t\t\tdata {\n\t\t\t\tInput string\n\t\t\t}\n\t\t\taction {\n\t\t\t\tinfo Sprintf(\"%v\", JSONDecode($Input))\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {\"1\"},\n\t\t\"Conditions\": {\"true\"},\n\t}))\n\n\tcases := []struct {\n\t\tsource string\n\t\tresult string\n\t}{\n\t\t{`\"test\"`, `{\"type\":\"info\",\"error\":\"test\"}`},\n\t\t{`[\"test\"]`, `{\"type\":\"info\",\"error\":\"[test]\"}`},\n\t\t{`{\"test\":1}`, `{\"type\":\"info\",\"error\":\"map[test:1]\"}`},\n\t\t{`[{\"test\":1}]`, `{\"type\":\"info\",\"error\":\"[map[test:1]]\"}`},\n\t\t{`{\"test\":1`, `{\"type\":\"panic\",\"error\":\"unexpected end of JSON input\"}`},\n\t}\n\n\tfor _, v := range cases {\n\t\tassert.EqualError(t, postTx(contract, &url.Values{\"Input\": {v.source}}), v.result)\n\t}\n}\n\nfunc TestBytesToString(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tcontract := randName(\"BytesToString\")\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + contract + ` {\n\t\t\tdata {\n\t\t\t\tData bytes\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = BytesToString($Data)\n\t\t\t}\n\t\t}`},\n\t\t\"Conditions\":    {\"true\"},\n\t\t\"ApplicationId\": {\"1\"},\n\t}))\n\n\tcontent := crypto.RandSeq(100)\n\t_, res, err := postTxResult(contract, &contractParams{\n\t\t\"Data\": []byte(content),\n\t})\n\tassert.NoError(t, err)\n\tassert.Equal(t, content, res)\n}\n\nfunc TestMoneyDigits(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tcontract := randName(\"MoneyDigits\")\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + contract + ` {\n\t\t\tdata {\n\t\t\t\tValue money\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = $Value\n\t\t\t}\n\t\t}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Conditions\":    {\"true\"},\n\t}))\n\n\t_, result, err := postTxResult(contract, &url.Values{\n\t\t\"Value\": {\"1\"},\n\t})\n\tassert.NoError(t, err)\n\n\td := decimal.New(1, int32(consts.MoneyDigits))\n\tassert.Equal(t, d.StringFixed(0), result)\n}\n\nfunc TestMemoryLimit(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tcontract := randName(\"Contract\")\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + contract + ` {\n\t\t\tdata {\n\t\t\t\tCount int \"optional\"\n\t\t\t}\n\t\t\taction {\n\t\t\t\tvar a array\n\t\t\t\twhile (true) {\n\t\t\t\t\t$Count = $Count + 1\n\t\t\t\t\ta[Len(a)] = JSONEncode(a)\n\t\t\t\t}\n\t\t\t}\n\t\t}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Conditions\":    {\"true\"},\n\t}))\n\n\tassert.EqualError(t, postTx(contract, &url.Values{}), `{\"type\":\"panic\",\"error\":\"Memory limit exceeded\"}`)\n}\n\nfunc TestStack(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tparent := randName(\"Parent\")\n\tchild := randName(\"Child\")\n\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + child + ` {\n\t\t\taction {\n\t\t\t\t$result = $stack\n\t\t\t}\n\t\t}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Conditions\":    {\"true\"},\n\t}))\n\n\tassert.NoError(t, postTx(\"NewContract\", &url.Values{\n\t\t\"Value\": {`contract ` + parent + ` {\n\t\t\taction {\n\t\t\t\tvar arr array\n\t\t\t\tarr[0] = $stack\n\t\t\t\tarr[1] = ` + child + `()\n\t\t\t\t$result = arr\n\t\t\t}\n\t\t}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t\t\"Conditions\":    {\"true\"},\n\t}))\n\n\t_, res, err := postTxResult(parent, &url.Values{})\n\tassert.NoError(t, err)\n\tassert.Equal(t, fmt.Sprintf(\"[[@1%s] [@1%[1]s @1%s]]\", parent, child), res)\n}\n\nfunc TestPageHistory(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`page`)\n\tvalue := `P(test,test paragraph)`\n\n\tform := url.Values{\"Name\": {name}, \"Value\": {value}, \"ApplicationId\": {`1`},\n\t\t\"Menu\": {\"default_menu\"}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\n\tvar ret listResult\n\tassert.NoError(t, sendGet(`list/pages`, nil, &ret))\n\tid := strconv.FormatInt(ret.Count, 10)\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\"Id\": {id}, \"Value\": {\"Div(style){ok}\"}}))\n\tassert.NoError(t, postTx(`EditPage`, &url.Values{\"Id\": {id}, \"Conditions\": {\"true\"}}))\n\n\tform = url.Values{\"Name\": {randName(`menu`)}, \"Value\": {`MenuItem(First)MenuItem(Second)`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewMenu`, &form))\n\n\tassert.NoError(t, sendGet(`list/menu`, nil, &ret))\n\tidmenu := strconv.FormatInt(ret.Count, 10)\n\tassert.NoError(t, postTx(`EditMenu`, &url.Values{\"Id\": {idmenu}, \"Conditions\": {\"true\"}}))\n\tassert.NoError(t, postTx(`EditMenu`, &url.Values{\"Id\": {idmenu}, \"Value\": {\"MenuItem(Third)\"}}))\n\tassert.NoError(t, postTx(`EditMenu`, &url.Values{\"Id\": {idmenu},\n\t\t\"Value\": {\"MenuItem(Third)\"}, \"Conditions\": {\"false\"}}))\n\n\tform = url.Values{\"Value\": {`contract C` + name + `{ action {}}`},\n\t\t\"ApplicationId\": {`1`}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\t_, idCont, err := postTxResult(`NewContract`, &form)\n\tassert.NoError(t, err)\n\tassert.NoError(t, postTx(`EditContract`, &url.Values{\"Id\": {idCont},\n\t\t\"Value\": {`contract C` + name + `{ action {Println(\"OK\")}}`}, \"Conditions\": {\"true\"}}))\n\n\tform = url.Values{`Value`: {`contract Get` + name + ` {\n\t\tdata {\n\t\t\tIdPage int\n\t\t\tIdMenu int\n\t\t\tIdCont int\n\t\t}\n\t\taction {\n\t\t\tvar ret array\n\t\t\tret = GetHistory(\"pages\", $IdPage)\n\t\t\t$result = Str(Len(ret))\n\t\t\tret = GetHistory(\"menu\", $IdMenu)\n\t\t\t$result = $result + Str(Len(ret))\n\t\t\tret = GetHistory(\"contracts\", $IdCont)\n\t\t\t$result = $result + Str(Len(ret))\n\t\t}\n\t}`}, \"ApplicationId\": {`1`}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tform = url.Values{`Value`: {`contract GetRow` + name + ` {\n\t\tdata {\n\t\t\tIdPage int\n\t\t}\n\t\taction {\n\t\t\tvar ret array\n\t\t\tvar row got map\n\t\t\tret = GetHistory(\"pages\", $IdPage)\n\t\t\trow = ret[1]\n\t\t\tgot = GetHistoryRow(\"pages\", $IdPage, Int(row[\"id\"]))\n\t\t\tif got[\"block_id\"] != row[\"block_id\"] {\n\t\t\t\terror \"GetPageHistory\"\n\t\t\t}\n\t\t}\n\t}`}, \"ApplicationId\": {`1`}, `Conditions`: {`true`}}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\t_, msg, err := postTxResult(`Get`+name, &url.Values{\"IdPage\": {id}, \"IdMenu\": {idmenu},\n\t\t\"IdCont\": {idCont}})\n\tassert.NoError(t, err)\n\tassert.Equal(t, `231`, msg)\n\n\tform = url.Values{\"Name\": {name + `1`}, \"Value\": {value}, \"ApplicationId\": {`1`},\n\t\t\"Menu\": {\"default_menu\"}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\n\tassert.NoError(t, postTx(`Get`+name, &url.Values{\"IdPage\": {converter.Int64ToStr(\n\t\tconverter.StrToInt64(id) + 1)}, \"IdMenu\": {idmenu}, \"IdCont\": {idCont}}))\n\n\tassert.EqualError(t, postTx(`Get`+name, &url.Values{\"IdPage\": {`1000000`}, \"IdMenu\": {idmenu},\n\t\t\"IdCont\": {idCont}}), `{\"type\":\"panic\",\"error\":\"Record has not been found\"}`)\n\n\tassert.NoError(t, postTx(`GetRow`+name, &url.Values{\"IdPage\": {id}}))\n\n\tvar retTemp contentResult\n\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {fmt.Sprintf(`GetHistory(MySrc, \"pages\", %s)`,\n\t\tid)}}, &retTemp))\n\n\tif len(RawToString(retTemp.Tree)) < 400 {\n\t\tt.Error(fmt.Errorf(`wrong tree %s`, RawToString(retTemp.Tree)))\n\t}\n}\n"
  },
  {
    "path": "packages/api/table.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype columnInfo struct {\n\tName string `json:\"name\"`\n\tType string `json:\"type\"`\n\tPerm string `json:\"perm\"`\n}\n\ntype tableResult struct {\n\tName       string       `json:\"name\"`\n\tInsert     string       `json:\"insert\"`\n\tNewColumn  string       `json:\"new_column\"`\n\tUpdate     string       `json:\"update\"`\n\tRead       string       `json:\"read,omitempty\"`\n\tFilter     string       `json:\"filter,omitempty\"`\n\tConditions string       `json:\"conditions\"`\n\tAppID      string       `json:\"app_id\"`\n\tColumns    []columnInfo `json:\"columns\"`\n}\n\nfunc getTableHandler(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\tprefix := client.Prefix()\n\n\ttable := &sqldb.Table{}\n\ttable.SetTablePrefix(prefix)\n\n\t_, err := table.Get(nil, strings.ToLower(params[\"name\"]))\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting table\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tif len(table.Name) == 0 {\n\t\terrorResponse(w, errTableNotFound.Errorf(params[\"name\"]))\n\t\treturn\n\t}\n\n\tvar columnsMap map[string]string\n\terr = json.Unmarshal([]byte(table.Columns), &columnsMap)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"Unmarshalling table columns to json\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tcolumns := make([]columnInfo, 0)\n\tfor key, value := range columnsMap {\n\t\tcolType, err := sqldb.NewDbTransaction(nil).GetColumnType(prefix+`_`+params[\"name\"], key)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting column type from db\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tcolumns = append(columns, columnInfo{\n\t\t\tName: key,\n\t\t\tPerm: value,\n\t\t\tType: colType,\n\t\t})\n\t}\n\n\tjsonResponse(w, &tableResult{\n\t\tName:       table.Name,\n\t\tInsert:     table.Permissions.Insert,\n\t\tNewColumn:  table.Permissions.NewColumn,\n\t\tUpdate:     table.Permissions.Update,\n\t\tRead:       table.Permissions.Read,\n\t\tFilter:     table.Permissions.Filter,\n\t\tConditions: table.Conditions,\n\t\tAppID:      converter.Int64ToStr(table.AppID),\n\t\tColumns:    columns,\n\t})\n}\n"
  },
  {
    "path": "packages/api/tables.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype tableInfo struct {\n\tName  string `json:\"name\"`\n\tCount string `json:\"count\"`\n}\n\ntype tablesResult struct {\n\tCount int64       `json:\"count\"`\n\tList  []tableInfo `json:\"list\"`\n}\n\nfunc getTablesHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &paginatorForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadGateway)\n\t\treturn\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\tprefix := client.Prefix()\n\n\ttable := &sqldb.Table{}\n\ttable.SetTablePrefix(prefix)\n\n\tcount, err := table.Count()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting records count from tables\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\trows, err := sqldb.GetDB(nil).Table(table.TableName()).Where(\"ecosystem = ?\", client.EcosystemID).Offset(form.Offset).Limit(form.Limit).Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tlist, err := sqldb.GetResult(rows)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting names from tables\")\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tresult := &tablesResult{\n\t\tCount: count,\n\t\tList:  make([]tableInfo, len(list)),\n\t}\n\tfor i, item := range list {\n\t\terr = sqldb.GetTableQuery(item[\"name\"], client.EcosystemID).Count(&count).Error\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting count from table\")\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\n\t\tresult.List[i].Name = item[\"name\"]\n\t\tresult.List[i].Count = converter.Int64ToStr(count)\n\t}\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/tables_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTables(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret tablesResult\n\terr := sendGet(`tables`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif int64(ret.Count) < 7 {\n\t\tt.Error(fmt.Errorf(`The number of tables %d < 7`, ret.Count))\n\t\treturn\n\t}\n}\n\nfunc TestTable(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret tableResult\n\terr := sendGet(`table/keys`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret.Columns) == 0 {\n\t\tt.Errorf(`Wrong result columns`)\n\t\treturn\n\t}\n\terr = sendGet(`table/contracts`, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nfunc TestTableName(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform := url.Values{\"Name\": {`test`}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \"index\": \"0\", \n\t\t\"conditions\":{\"update\":\"true\", \"read\":\"true\"}}]`}, \"ApplicationId\": {\"1\"},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.EqualError(t, postTx(`NewTable`, &form),\n\t\t`{\"type\":\"panic\",\"error\":\"Name test must only contain latin, digit and '_', '-' characters\"}`)\n\n\tform = url.Values{\"Name\": {`latin`}, \"Columns\": {`[{\"name\":\"test\",\"type\":\"varchar\", \"index\": \"0\", \n\t\t\"conditions\":{\"update\":\"true\", \"read\":\"true\"}}]`}, \"ApplicationId\": {\"1\"},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.EqualError(t, postTx(`NewTable`, &form),\n\t\t`{\"type\":\"panic\",\"error\":\"Name latin must only contain latin, digit and '_', '-' characters\"}`)\n\n\tname := randName(`tbl`)\n\tform = url.Values{\"Name\": {`tbl-` + name}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \"index\": \"0\", \n\t  \"conditions\":{\"update\":\"true\", \"read\":\"true\"}}]`}, \"ApplicationId\": {\"100\"},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\terr := postTx(`NewTable`, &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\taction { \n\t\t\tDBInsert(\"tbl-` + name + `\", {\"MyName\": \"test\"})\n\t\t\tDBUpdate(\"tbl-` + name + `\", 1, {\"MyName\": \"New test\"})\n\t\t}}`}, \"ApplicationId\": {`100`}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\terr = postTx(\"NewContract\", &form)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = postTx(name, &url.Values{})\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tvar ret tableResult\n\terr = sendGet(`table/tbl-`+name, nil, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif len(ret.Columns) == 0 || ret.AppID != `100` {\n\t\tt.Errorf(`wrong table columns or app_id`)\n\t\treturn\n\t}\n\tvar retList listResult\n\terr = sendGet(`list/tbl-`+name, nil, &retList)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif retList.Count != 1 {\n\t\tt.Errorf(`wrong table count`)\n\t\treturn\n\t}\n\tforTest := tplList{\n\t\t{`DBFind(tbl-` + name + `,my).Columns(\"id,myname\").WhereId(1)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"myname\"],\"data\":[[\"1\",\"New test\"]],\"name\":\"tbl-` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\"],\"whereid\":\"1\"}}]`},\n\t}\n\tvar retCont contentResult\n\tfor _, item := range forTest {\n\t\terr := sendPost(`content`, &url.Values{`template`: {item.input}}, &retCont)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tif RawToString(retCont.Tree) != item.want {\n\t\t\tt.Error(fmt.Errorf(`wrong tree %s != %s`, RawToString(retCont.Tree), item.want))\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestJSONTable(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`json`)\n\tform := url.Values{\"Name\": {name}, \"Columns\": {`[{\"name\":\"MyName\",\"type\":\"varchar\", \"index\": \"0\", \n\t\t\"conditions\":\"true\"}, {\"name\":\"Doc\", \"type\":\"json\",\"index\": \"0\", \"conditions\":\"true\"}]`},\n\t\t\"ApplicationId\": {`1`}, \"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tcheckGet := func(want string) {\n\t\t_, msg, err := postTxResult(name+`Get`, &url.Values{\"Id\": {`2`}})\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, want, msg)\n\t}\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\taction { \n\t\t\tvar ret1, ret2 int\n\t\t\tret1 = DBInsert(\"` + name + `\", {MyName: \"test\",Doc: \"{\\\"type\\\": \\\"0\\\"}\"})\n\t\t\tvar mydoc map\n\t\t\tmydoc[\"type\"] = \"document\"\n\t\t\tmydoc[\"ind\"] = 2\n\t\t\tmydoc[\"check\"] = \"99\"\n\t\t\tmydoc[\"doc\"] = \"Some text.\"\n\t\t\tret2 = DBInsert(\"` + name + `\", {MyName: \"test2\",Doc: mydoc})\n\t\t\tDBInsert(\"` + name + `\", {MyName: \"test3\",Doc: \"{\\\"title\\\": {\\\"name\\\":\\\"Test att\\\",\\\"text\\\":\\\"low\\\"}}\"})\n\t\t\tDBInsert(\"` + name + `\", {MyName: \"test4\",doc: \"{\\\"languages\\\": {\\\"arr_id\\\":{\\\"1\\\":\\\"0\\\",\\\"2\\\":\\\"0\\\",\\\"3\\\":\\\"0\\\"}}}\"})\n\t\t\tDBInsert(\"` + name + `\", {MyName: \"test5\",Doc: \"{\\\"app_id\\\": \\\"33\\\"}\"})\n\t\t}}`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `Get {\n\t\t\tdata {\n\t\t\t\tId int\n\t\t\t}\n\t\t\taction {\n\t\t\t\tvar ret map\n\t\t\t\tvar list array\n\t\t\t\tvar one out tmp where empty string\n\t\t\t\tret = DBFind(\"` + name + `\").Columns(\"Myname,doc,Doc->Ind\").WhereId($Id).Row()\n\t\t\t\tout = ret[\"doc.ind\"]\n\t\t\t\tout = out + DBFind(\"` + name + `\").Columns(\"myname,doc->Type\").WhereId($Id).One(\"Doc->type\")\n\t\t\t\tlist = DBFind(\"` + name + `\").Columns([\"Myname\", \"doc\", \"Doc->Ind\"]).Where({\"Doc->ind\": \"101\"})\n\t\t\t\tout = out + Str(Len(list))\n\t\t\t\ttmp = DBFind(\"` + name + `\").Columns(\"doc->title->name\").WhereId(3).One(\"doc->title->name\")\n\t\t\t\twhere = DBFind(\"` + name + `\").Columns(\"doc->title->name\").Where({\"doc->title->text\":\"low\"}).One(\"doc->title->name\")\n\t\t\t\tone = DBFind(\"` + name + `\").Where({\"doc->title->text\":\"low\"}).One(\"doc->title->text\")\n\t\t\t\tempty = DBFind(\"` + name + `\").WhereId(4).One(\"doc->languages->arr_id->2\")\n\t\t\t\t$result = out + Str(DBFind(\"` + name + `\").WhereId($Id).One(\"doc->check\")) + tmp + where +one + empty\n\t\t\t}\n\t\t}`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `Upd {\n\t\taction {\n\t\t\tDBUpdate(\"` + name + `\", 1, {\"Doc\": \"{\\\"type\\\": \\\"doc\\\", \\\"ind\\\": \\\"3\\\", \\\"check\\\": \\\"33\\\"}\"})\n\t\t\tvar mydoc map\n\t\t\tmydoc[\"type\"] = \"doc\"\n\t\t\tmydoc[\"doc\"] = \"Some test text.\"\n\t\t\tDBUpdate(\"` + name + `\", 2, {\"myname\": \"test3\", \"Doc\": mydoc})\n\t\t}}`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + `UpdOne {\n\t\t\tdata {\n\t\t\t\tType int\n\t\t\t}\n\t\t\taction {\n\t\t\t\tDBUpdate(\"` + name + `\", 1, {\"myname\": \"New name\", \"Doc->Ind\": $Type,\n\t\t\t\t    \"Doc->type\": \"new\\\"doc\\\" val\"})\n\t\t\t\tDBUpdate(\"` + name + `\", 2, {\"myname\": \"New name\",\"Doc->Ind\": $Type,\n\t\t\t\t   \"Doc->type\": \"new\\\"doc\\\"\"})\n\t\t\t\tDBUpdate(\"` + name + `\", 3, {\"doc->flag\": \"Flag\",\"doc->sub\": 100})\n\t\t\t\tDBUpdate(\"` + name + `\", 3, {\"doc->temp\":\"Temp\"})\n\t\t  }}\n\t\t`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\tassert.NoError(t, postTx(name, &url.Values{}))\n\n\tcheckGet(`2document099Test attTest attlow0`)\n\n\tassert.NoError(t, postTx(name+`Upd`, &url.Values{}))\n\tcheckGet(`doc0Test attTest attlow0`)\n\n\tassert.NoError(t, postTx(name+`UpdOne`, &url.Values{\"Type\": {\"101\"}}))\n\tcheckGet(`101new\"doc\"2Test attTest attlow0`)\n\n\tform = url.Values{\"Name\": {`res` + name}, \"Value\": {`contract res` + name + ` {\n\t\tdata {\n\t\t\tId int\n\t\t}\n\t\taction { \n\t\t\t$result = DBFind(\"contracts\").WhereId($Id).Row()\n\t\t}}`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\tform = url.Values{\"Name\": {`run` + name}, \"Value\": {`contract run` + name + ` {\n\t\taction { \n\t\t\t$temp = res` + name + `(\"Id\",10)\n\t\t\t$result = $temp[\"id\"]\n\t\t}}`}, \"ApplicationId\": {`1`},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\t_, msg, err := postTxResult(`run`+name, &url.Values{})\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"10\", msg)\n\n\tforTest := tplList{\n\t\t{`DBFind(` + name + `).Columns(\"id,doc->app_id\").WhereId(5).Vars(buffer)Span(#buffer_doc_app_id#)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc.app_id\"],\"data\":[[\"5\",\"33\"]],\"name\":\"` + name + `\",\"types\":[\"text\",\"text\"],\"whereid\":\"5\"}},{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"33\"}]}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id\").Where({\"doc->title->text\":\"low\"})`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"data\":[[\"3\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\"],\"where\":\"{\"doc-\\u003etitle-\\u003etext\":\"low\"}\"}}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id,doc->title->name\").WhereId(3).Vars(prefix)Div(){#prefix_id# = #prefix_doc_title_name#}`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc.title.name\"],\"data\":[[\"3\",\"Test att\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\"],\"whereid\":\"3\"}},{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"3 = Test att\"}]}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id,doc->languages->arr_id\").WhereId(4).Custom(aa){Span(#doc.languages.arr_id#)}`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc.languages.arr_id\",\"aa\"],\"data\":[[\"4\",\"{\"1\": \"0\", \"2\": \"0\", \"3\": \"0\"}\",\"[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"{\\\\\"1\\\\\": \\\\\"0\\\\\", \\\\\"2\\\\\": \\\\\"0\\\\\", \\\\\"3\\\\\": \\\\\"0\\\\\"}\"}]}]\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\",\"tags\"],\"whereid\":\"4\"}}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id,doc->title->name\").WhereId(3)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc.title.name\"],\"data\":[[\"3\",\"Test att\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\"],\"whereid\":\"3\"}}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"doc\").WhereId(3)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"doc\",\"id\"],\"data\":[[\"{\"sub\": \"100\", \"flag\": \"Flag\", \"temp\": \"Temp\", \"title\": {\"name\": \"Test att\", \"text\": \"low\"}}\",\"3\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\"],\"whereid\":\"3\"}}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id,doc,doc->type\").Where({doc->ind:101, doc->check:33})`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc\",\"doc.type\"],\"data\":[[\"1\",\"{\"ind\": \"101\", \"type\": \"new\\\\\"doc\\\\\" val\", \"check\": \"33\"}\",\"new\"doc\" val\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\",\"text\"],\"where\":\"{doc-\\u003eind:101, doc-\\u003echeck:33}\"}}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id,doc,doc->type\").WhereId(2).Vars(my)\n\t\t\tSpan(#my_id##my_doc_type#)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc\",\"doc.type\"],\"data\":[[\"2\",\"{\"doc\": \"Some test text.\", \"ind\": \"101\", \"type\": \"new\\\\\"doc\\\\\"\"}\",\"new\"doc\"\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\",\"text\"],\"whereid\":\"2\"}},{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"2new\"doc\"\"}]}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"id,doc->type\").WhereId(2)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"doc.type\"],\"data\":[[\"2\",\"new\"doc\"\"]],\"name\":\"` + name + `\",\"source\":\"my\",\"types\":[\"text\",\"text\"],\"whereid\":\"2\"}}]`},\n\t\t{`DBFind(` + name + `,my).Columns(\"doc->type\").Order(id).Custom(mytype, OK:#doc.type#)`,\n\t\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"doc.type\",\"id\",\"mytype\"],\"data\":[[\"new\"doc\" val\",\"1\",\"[{\"tag\":\"text\",\"text\":\"OK:new\"doc\" val\"}]\"],[\"new\"doc\"\",\"2\",\"[{\"tag\":\"text\",\"text\":\"OK:new\"doc\"\"}]\"],[\"\",\"3\",\"[{\"tag\":\"text\",\"text\":\"OK:NULL\"}]\"],[\"\",\"4\",\"[{\"tag\":\"text\",\"text\":\"OK:NULL\"}]\"],[\"\",\"5\",\"[{\"tag\":\"text\",\"text\":\"OK:NULL\"}]\"]],\"name\":\"` + name + `\",\"order\":\"id\",\"source\":\"my\",\"types\":[\"text\",\"text\",\"tags\"]}}]`},\n\t}\n\tvar ret contentResult\n\tfor i, item := range forTest {\n\t\tif i > 100 {\n\t\t\tbreak\n\t\t}\n\t\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {item.input}}, &ret))\n\t\tassert.Equal(t, item.want, RawToString(ret.Tree))\n\t}\n}\n\nfunc TestTableDesc(t *testing.T) {\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tname := randName(`tbl`)\n\tform := url.Values{\"Name\": {name}, \"Columns\": {`[{\"name\":\"desc\",\"type\":\"varchar\", \"index\": \"0\", \n\t  \"conditions\":{\"update\":\"true\", \"read\":\"true\"}}]`}, \"ApplicationId\": {\"1\"},\n\t\t\"Permissions\": {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`}}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\taction { \n\t\t\tDBInsert(\"` + name + `\", {\"desc\": \"test\"})\n\t\t\tDBUpdate(\"` + name + `\", 1, {\"desc\": \"new test\"})\n\t\t\t$result = DBFind(\"` + name + `\").Columns(\"desc\").WhereId(1).One(\"desc\")\n\t\t   var vals map\n\t\t   vals = DBRow(\"pages\").Columns(\"NAME, menu\").Where({id:1})\n\t\t   $result = $result + vals[\"name\"]\n\t\t}}`}, \"ApplicationId\": {\"1\"},\n\t\t\"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\t_, msg, err := postTxResult(name, &url.Values{})\n\tassert.NoError(t, err)\n\tif msg != `new testdefault_page` {\n\t\tt.Errorf(`wrong msg %s`, msg)\n\t}\n\n\tform = url.Values{\n\t\t\"template\": {`DBFind(\"` + name + `\", src1)`},\n\t}\n\tvar ret contentResult\n\tassert.NoError(t, sendPost(`content`, &form, &ret))\n\n\tif RawToString(ret.Tree) != `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"desc\"],\"data\":[[\"1\",\"new test\"]],\"name\":\"`+name+`\",\"source\":\"src1\",\"types\":[\"text\",\"text\"]}}]` {\n\t\tt.Error(fmt.Errorf(`wrong tree %s`, RawToString(ret.Tree)))\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "packages/api/template_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype tplItem struct {\n\tinput string\n\twant  string\n}\n\ntype tplList []tplItem\n\nfunc TestAPI(t *testing.T) {\n\tvar (\n\t\tret               contentResult\n\t\tretHash, retHash2 hashResult\n\t\terr               error\n\t\tmsg               string\n\t)\n\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tname := randName(`page`)\n\tvalue := `Div(,#ecosystem_id#)\n\tDiv(,#key_id#)\n\tDiv(,#role_id#)`\n\tform := url.Values{\"Name\": {name}, \"Value\": {value}, \"ApplicationId\": {`1`},\n\t\t\"Menu\": {`default_menu`}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(`NewPage`, &form))\n\n\tassert.NoError(t, sendPost(`content/hash/`+name, &url.Values{}, &retHash))\n\tif len(retHash.Hash) != 64 {\n\t\tt.Error(`wrong hash ` + retHash.Hash)\n\t\treturn\n\t}\n\tform = url.Values{\"Name\": {name}, \"Value\": {`contract ` + name + ` {\n\t\taction {\n\t\t\t$result = $key_id\n\t\t}}`}, \"ApplicationId\": {`1`}, \"Conditions\": {`ContractConditions(\"MainCondition\")`}}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\t_, msg, err = postTxResult(name, &url.Values{})\n\tassert.NoError(t, err)\n\n\tgAddress = ``\n\tgPrivate = ``\n\tgPublic = ``\n\tgAuth = ``\n\tassert.NoError(t, sendPost(`content/hash/`+name, &url.Values{`ecosystem`: {`1`}, `keyID`: {msg}, `roleID`: {`0`}},\n\t\t&retHash2))\n\tif retHash.Hash != retHash2.Hash {\n\t\tt.Error(`Wrong hash`)\n\t\treturn\n\t}\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = sendPost(`content/page/default_page`, &url.Values{}, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tfor _, item := range forTest {\n\t\terr := sendPost(`content`, &url.Values{`template`: {item.input}}, &ret)\n\t\tif err != nil {\n\t\t\tt.Error(err)\n\t\t\treturn\n\t\t}\n\t\tif RawToString(ret.Tree) != item.want {\n\t\t\tt.Error(fmt.Errorf(\"wrong tree \\r\\n%s != \\r\\n%s\", RawToString(ret.Tree), item.want))\n\t\t\treturn\n\t\t}\n\t}\n\terr = sendPost(`content/page/mypage`, &url.Values{}, &ret)\n\tif err != nil && err.Error() != `404 {\"error\":\"E_NOTFOUND\",\"msg\":\"Page not found\"}` {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\terr = sendPost(`content/menu/default_menu`, &url.Values{}, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n}\n\nvar forTest = tplList{\n\t{`DBFind(contracts, src).Columns(\"id\").Where({\"app_id\": 1, ,\"id\": {\"$gt\": 2}})`,\n\t\t`[{\"tag\":\"text\",\"text\":\"unexpected comma\"}]`},\n\t{`DBFind(contracts, src).Columns(\"id\").Where({\"app_id\": 1, \"id\": {\"$gt\": 2},})`,\n\t\t`[{\"tag\":\"text\",\"text\":\"unexpected comma\"}]`},\n\t{`SetVar(w_filter, ` + \"`\" + `\"id\": {\"$lt\": \"2\"}` + \"`\" + `)SetVar(w, {#w_filter# #w_search#})\n\t\t  DBFind(\"contracts\", src).Columns(\"id,name\").Where(#w#)Table(src)`,\n\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"1\",\"MainCondition\"]],\"name\":\"contracts\",\"source\":\"src\",\"types\":[\"text\",\"text\"],\"where\":\"{\"id\": {\"$lt\": \"2\"} }\"}},{\"tag\":\"table\",\"attr\":{\"source\":\"src\"}}]`},\n\t{`DBFind(\"contracts\", src).Columns(\"id,name\").Where({\"id\": {\"$lt\": \"2\"} })`,\n\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"1\",\"MainCondition\"]],\"name\":\"contracts\",\"source\":\"src\",\"types\":[\"text\",\"text\"],\"where\":\"{\"id\": {\"$lt\": \"2\"} }\"}}]`},\n\t{`SetVar(where, {\"$or\": [\"name\": #poa#,\"valueN\": #poa#]})\n\t\tDBFind(contracts, src).Columns(\"id\").Where(#where#)`, `[{\"tag\":\"text\",\"text\":\"pq: column \"valuen\" does not exist in query select \"id\" from \"1_contracts\" where (\"name\" = '' or \"valuen\" = '') order by id [[]]\"}]`},\n\t{`DBFind(\"@1roles_participants\", src).Where({\"ecosystem\": #ecosystem_id#, \"role->id\": {\"$in\": []}, \"member->member_id\": #key_id#, \"deleted\": 0})`, `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"role\",\"member\",\"appointed\",\"date_created\",\"date_deleted\",\"deleted\",\"ecosystem\"],\"data\":[],\"name\":\"@1roles_participants\",\"source\":\"src\",\"types\":[],\"where\":\"{\"ecosystem\": 1, \"role-\\u003eid\": {\"$in\": []}, \"member-\\u003emember_id\": 2665397054248150876, \"deleted\": 0}\"}}]`},\n\t{`DBFind(\"@1roles_participants\").Where({\"ecosystem\": #ecosystem_id#, \"role->id\": {\"$in\": []}, \"member->member_id\": #key_id#, \"deleted\": 0}).Vars(v)`, `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"role\",\"member\",\"appointed\",\"date_created\",\"date_deleted\",\"deleted\",\"ecosystem\"],\"data\":[],\"name\":\"@1roles_participants\",\"types\":[],\"where\":\"{\"ecosystem\": 1, \"role-\\u003eid\": {\"$in\": []}, \"member-\\u003emember_id\": 2665397054248150876, \"deleted\": 0}\"}}]`},\n\t{`DBFind(@1pages).Where({{id:{$neq:5}}, {id:2}, id:{$neq:6}, $or:[id:6, {id:1}, {id:2}, id:3]}).Columns(\"id,name\").Order(id)`, `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"1\",\"developer_index\"],[\"3\",\"notifications\"]],\"name\":\"@1pages\",\"order\":\"id\",\"types\":[\"text\",\"text\"],\"where\":\"{{id:{$neq:5}}, {id:2}, id:{$neq:6}, $or:[id:6, {id:1}, {id:2}, id:3]}\"}}]`},\n\t{`DBFind(@1pages).Where({id:[{$neq:5},{$neq:4}, 2], name:{$neq: Edit}}).Columns(\"id,name\")`,\n\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"2\",\"developer_index\"]],\"name\":\"@1pages\",\"types\":[\"text\",\"text\"],\"where\":\"{id:[{$neq:5},{$neq:4}, 2], name:{$neq: Edit}}\"}}]`},\n\t{`DBFind(@1pages).Where({id:3, name: {$neq:EditPage}, $or:[id:1, {id:5}, id:{$neq:2}, id:4]}).Columns(\"id,name\")`, `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"3\",\"notifications\"]],\"name\":\"@1pages\",\"types\":[\"text\",\"text\"],\"where\":\"{id:3, name: {$neq:EditPage}, $or:[id:1, {id:5}, id:{$neq:2}, id:4]}\"}}]`},\n\t{`DBFind(keys).Where(\"id='#key_id#'\").Columns(\"amount\").Vars(amount)`, `[{\"tag\":\"text\",\"text\":\"Where has wrong format\"}]`},\n\t{`SetVar(val, 123456789)Money(#val#)`, `[{\"tag\":\"text\",\"text\":\"0.000000000123456789\"}]`},\n\t{`SetVar(coltype, GetColumnType(members, member_name))Div(){#coltype#GetColumnType(none,none)GetColumnType()}`, `[{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"varchar\"}]}]`},\n\t{`DBFind(parameters, src_par).Columns(\"id\").Order([id]).Where({id:[{$gte:1}, {$lte:3}]}).Count(count)Span(#count#)`,\n\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"count\":\"3\",\"data\":[[\"1\"],[\"2\"],[\"3\"]],\"name\":\"parameters\",\"order\":\"[id]\",\"source\":\"src_par\",\"types\":[\"text\"],\"where\":\"{id:[{$gte:1}, {$lte:3}]}\"}},{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"3\"}]}]`},\n\t{`SetVar(coltype, GetColumnType(members, member_name))Div(){#coltype#GetColumnType(none,none)GetColumnType()}`, `[{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"varchar\"}]}]`},\n\t{`SetVar(where).(lim,3)DBFind(contracts, src).Columns(id).Order([{id:1}, {name:-1}]).Limit(#lim#).Custom(a){SetVar(where, #where# #id#)}\n\tDiv(){Table(src, \"=x\")}Div(){Table(src)}Div(){#where#}`,\n\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"a\"],\"data\":[[\"1\",\"null\"],[\"2\",\"null\"],[\"3\",\"null\"]],\"limit\":\"3\",\"name\":\"contracts\",\"order\":\"[{id:1}, {name:-1}]\",\"source\":\"src\",\"types\":[\"text\",\"tags\"]}},{\"tag\":\"div\",\"children\":[{\"tag\":\"table\",\"attr\":{\"columns\":[{\"Name\":\"x\",\"Title\":\"\"}],\"source\":\"src\"}}]},{\"tag\":\"div\",\"children\":[{\"tag\":\"table\",\"attr\":{\"source\":\"src\"}}]},{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\" 1 2 3\"}]}]`},\n\t{`SetVar(off, 10)DBFind(contracts, src_contracts).Columns(\"id\").Order(id).Limit(2).Offset(#off#).Custom(){}`,\n\t\t`[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"data\":[[\"11\"],[\"12\"]],\"limit\":\"2\",\"name\":\"contracts\",\"offset\":\"10\",\"order\":\"id\",\"source\":\"src_contracts\",\"types\":[\"text\"]}}]`},\n\t{`DBFind(contracts, src_pos).Columns(id).Where({id:[{$gte:1}, {$lte:3}]}).Order(id)\n\t\tForList(src_pos, Index: index){\n\t\t\tDiv(list-group-item) {\n\t\t\t\tDBFind(parameters, src_hol).Columns(id).Where({id: #id#}).Vars(\"ret\")\n\t\t\t\tSetVar(qq, #ret_id#)\n\t\t\t\tDiv(Body: #index# ForList=#id# DBFind=#ret_id# SetVar=#qq#)  \n\t\t\t}\n\t\t}`, `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"data\":[[\"1\"],[\"2\"],[\"3\"]],\"name\":\"contracts\",\"order\":\"id\",\"source\":\"src_pos\",\"types\":[\"text\"],\"where\":\"{id:[{$gte:1}, {$lte:3}]}\"}},{\"tag\":\"forlist\",\"attr\":{\"index\":\"index\",\"source\":\"src_pos\"},\"children\":[{\"tag\":\"div\",\"attr\":{\"class\":\"list-group-item\"},\"children\":[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"data\":[[\"1\"]],\"name\":\"parameters\",\"source\":\"src_hol\",\"types\":[\"text\"],\"where\":\"{id: 1}\"}},{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"1 ForList=1 DBFind=1 SetVar=1\"}]}]},{\"tag\":\"div\",\"attr\":{\"class\":\"list-group-item\"},\"children\":[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"data\":[[\"2\"]],\"name\":\"parameters\",\"source\":\"src_hol\",\"types\":[\"text\"],\"where\":\"{id: 2}\"}},{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"2 ForList=2 DBFind=2 SetVar=2\"}]}]},{\"tag\":\"div\",\"attr\":{\"class\":\"list-group-item\"},\"children\":[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\"],\"data\":[[\"3\"]],\"name\":\"parameters\",\"source\":\"src_hol\",\"types\":[\"text\"],\"where\":\"{id: 3}\"}},{\"tag\":\"div\",\"children\":[{\"tag\":\"text\",\"text\":\"3 ForList=3 DBFind=3 SetVar=3\"}]}]}]}]`},\n\t{`Data(Source: mysrc, Columns: \"startdate,enddate\", Data:\n\t\t2017-12-10 10:11,2017-12-12 12:13\n\t\t2017-12-17 16:17,2017-12-15 14:15\n\t).Custom(custom_id){\n\t\tSetVar(Name: vStartDate, Value: DateTime(DateTime: #startdate#, Format: \"YYYY-MM-DD HH:MI\"))\n\t\tSetVar(Name: vEndDate, Value: DateTime(DateTime: #enddate#, Format: \"YYYY-MM-DD HH:MI\"))\n\t\tSetVar(Name: vCmpDate, Value: CmpTime(#vStartDate#,#vEndDate#)) \n\t\tP(Body: #vStartDate# #vEndDate# #vCmpDate#)\n\t}.Custom(custom_name){\n\t\tP(Body: #vStartDate# #vEndDate# #vCmpDate#)\n\t}`,\n\t\t`[{\"tag\":\"data\",\"attr\":{\"columns\":[\"startdate\",\"enddate\",\"custom_id\",\"custom_name\"],\"data\":[[\"2017-12-10 10:11\",\"2017-12-12 12:13\",\"[{\"tag\":\"p\",\"children\":[{\"tag\":\"text\",\"text\":\"2017-12-10 10:11 2017-12-12 12:13 -1\"}]}]\",\"[{\"tag\":\"p\",\"children\":[{\"tag\":\"text\",\"text\":\"2017-12-10 10:11 2017-12-12 12:13 -1\"}]}]\"],[\"2017-12-17 16:17\",\"2017-12-15 14:15\",\"[{\"tag\":\"p\",\"children\":[{\"tag\":\"text\",\"text\":\"2017-12-17 16:17 2017-12-15 14:15 1\"}]}]\",\"[{\"tag\":\"p\",\"children\":[{\"tag\":\"text\",\"text\":\"2017-12-17 16:17 2017-12-15 14:15 1\"}]}]\"]],\"source\":\"mysrc\",\"types\":[\"text\",\"text\",\"tags\",\"tags\"]}}]`},\n\t{`Strong(SysParam(taxes_size))`,\n\t\t`[{\"tag\":\"strong\",\"children\":[{\"tag\":\"text\",\"text\":\"3\"}]}]`},\n\t{`SetVar(Name: vDateNow, Value: Now(\"YYYY-MM-DD HH:MI\")) \n\t\tSetVar(Name: simple, Value: TestFunc(my value)) \n\t\tSetVar(Name: vStartDate, Value: DateTime(DateTime: #vDateNow#, Format: \"YYYY-MM-DD HH:MI\"))\n\t\tSetVar(Name: vCmpStartDate, Value: CmpTime(#vStartDate#,#vDateNow#))\n\t\tSpan(#vCmpStartDate# #simple#)`,\n\t\t`[{\"tag\":\"span\",\"children\":[{\"tag\":\"text\",\"text\":\"-1 TestFunc(my value)\"}]}]`},\n\t{`Input(Type: text, Value: Now(MMYY))`,\n\t\t`[{\"tag\":\"input\",\"attr\":{\"type\":\"text\",\"value\":\"Now(MMYY)\"}}]`},\n\t{`Button(Body: LangRes(savex), Class: btn btn-primary, Contract: EditProfile, \n\t\tPage:members_list,).Alert(Text: $want_save_changesx$, \n\t\tConfirmButton: $yesx$, CancelButton: $nox$, Icon: question)`,\n\t\t`[{\"tag\":\"button\",\"attr\":{\"alert\":{\"cancelbutton\":\"$nox$\",\"confirmbutton\":\"$yesx$\",\"icon\":\"question\",\"text\":\"$want_save_changesx$\"},\"class\":\"btn btn-primary\",\"contract\":\"EditProfile\",\"page\":\"members_list\"},\"children\":[{\"tag\":\"text\",\"text\":\"savex\"}]}]`},\n\t{`Button(Body: button).Popup(Width: 100)`,\n\t\t`[{\"tag\":\"button\",\"attr\":{\"popup\":{\"width\":\"100\"}},\"children\":[{\"tag\":\"text\",\"text\":\"button\"}]}]`},\n\t{`Button(Body: button).Popup(Width: 100, Header: header)`,\n\t\t`[{\"tag\":\"button\",\"attr\":{\"popup\":{\"header\":\"header\",\"width\":\"100\"}},\"children\":[{\"tag\":\"text\",\"text\":\"button\"}]}]`},\n\t{`Button(Body: button).Popup(Header: header)`,\n\t\t`[{\"tag\":\"button\",\"children\":[{\"tag\":\"text\",\"text\":\"button\"}]}]`},\n\t{`Simple Strong(bold text)`,\n\t\t`[{\"tag\":\"text\",\"text\":\"Simple \"},{\"tag\":\"strong\",\"children\":[{\"tag\":\"text\",\"text\":\"bold text\"}]}]`},\n\t{`EcosysParam(gender, Source: mygender)`,\n\t\t`[{\"tag\":\"data\",\"attr\":{\"columns\":[\"id\",\"name\"],\"data\":[[\"1\",\"\"]],\"source\":\"mygender\",\"types\":[\"text\",\"text\"]}}]`},\n\t{`EcosysParam(new_table)`,\n\t\t`[{\"tag\":\"text\",\"text\":\"ContractConditions(\"MainCondition\")\"}]`},\n\t{`SetVar(varZero, 0) If(#varZero#>0) { the varZero should be hidden }\n\t\tSetVar(varNotZero, 1) If(#varNotZero#>0) { the varNotZero should be visible }\n\t\tIf(#varUndefined#>0) { the varUndefined should be hidden }`,\n\t\t`[{\"tag\":\"text\",\"text\":\"the varNotZero should be visible\"}]`},\n\t{`DateTime(1257894000)`,\n\t\t`[{\"tag\":\"text\",\"text\":\"` + time.Unix(1257894000, 0).Format(\"2006-01-02 15:04:05\") + `\"}]`},\n\t{`CmpTime(1257894000, 1257895000)CmpTime(1257895000, 1257894000)CmpTime(1257894000, 1257894000)`,\n\t\t`[{\"tag\":\"text\",\"text\":\"-110\"}]`},\n\t{`P(Guest = #guest_key#)`, `[{\"tag\":\"p\",\"children\":[{\"tag\":\"text\",\"text\":\"Guest = 4544233900443112470\"}]}]`},\n}\n\nfunc TestMoney(t *testing.T) {\n\tvar ret contentResult\n\tif err := keyLogin(1); err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tsize := 10000000\n\tmoney := make([]byte, size)\n\trand.Seed(time.Now().UnixNano())\n\tfor i := 0; i < size; i++ {\n\t\tmoney[i] = '0' + byte(rand.Intn(10))\n\t}\n\terr := sendPost(`content`, &url.Values{`template`: {`Money(` + string(money) + `)`}}, &ret)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tif RawToString(ret.Tree) != `[{\"tag\":\"text\",\"text\":\"invalid money value\"}]` {\n\t\tt.Errorf(`wrong value %s`, RawToString(ret.Tree))\n\t}\n}\n\nfunc TestCutoff(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tname := randName(`tbl`)\n\tform := url.Values{\n\t\t\"Name\": {name},\n\t\t\"Columns\": {`[\n\t\t\t{\"name\":\"name\",\"type\":\"varchar\", \"index\": \"1\", \"conditions\":\"true\"},\n\t\t\t{\"name\":\"long_text\", \"type\":\"text\", \"index\":\"0\", \"conditions\":\"true\"},\n\t\t\t{\"name\":\"short_text\", \"type\":\"varchar\", \"index\":\"0\", \"conditions\":\"true\"}\n\t\t\t]`},\n\t\t\"Permissions\":   {`{\"insert\": \"true\", \"update\" : \"true\", \"new_column\": \"true\"}`},\n\t\t\"ApplicationId\": {\"1\"},\n\t}\n\tassert.NoError(t, postTx(`NewTable`, &form))\n\tform = url.Values{\n\t\t\"Name\": {name},\n\t\t\"Value\": {`\n\t\t\tcontract ` + name + ` {\n\t\t\t\tdata {\n\t\t\t\t\tLongText string\n\t\t\t\t\tShortText string\n\t\t\t\t}\n\t\t\t\taction {\n\t\t\t\t\tDBInsert(\"` + name + `\", {name: \"test\", long_text: $LongText, short_text: $ShortText})\n\t\t\t\t}\n\t\t\t}\n\t\t`},\n\t\t\"Conditions\":    {`true`},\n\t\t\"ApplicationId\": {\"1\"},\n\t}\n\tassert.NoError(t, postTx(`NewContract`, &form))\n\n\tshortText := crypto.RandSeq(30)\n\tlongText := crypto.RandSeq(100)\n\n\tassert.NoError(t, postTx(name, &url.Values{\n\t\t\"ShortText\": {shortText},\n\t\t\"LongText\":  {longText},\n\t}))\n\n\tvar ret contentResult\n\ttemplate := `DBFind(Name: ` + name + `, Source: mysrc).Cutoff(\"short_text,long_text\")`\n\tstart := time.Now()\n\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {template}}, &ret))\n\tduration := time.Since(start)\n\tif int(duration.Seconds()) > 0 {\n\t\tt.Errorf(`Too much time for template parsing`)\n\t\treturn\n\t}\n\tassert.NoError(t, postTx(name, &url.Values{\n\t\t\"ShortText\": {shortText},\n\t\t\"LongText\":  {longText},\n\t}))\n\n\ttemplate = `DBFind(\"` + name + `\", mysrc).Columns(\"id,name,short_text,long_text\").Cutoff(\"short_text,long_text\").WhereId(2).Vars(prefix)`\n\tassert.NoError(t, sendPost(`content`, &url.Values{`template`: {template}}, &ret))\n\n\tlinkLongText := fmt.Sprintf(\"/data/1_%s/2/long_text/%x\", name, md5.Sum([]byte(longText)))\n\n\twant := `[{\"tag\":\"dbfind\",\"attr\":{\"columns\":[\"id\",\"name\",\"short_text\",\"long_text\"],\"cutoff\":\"short_text,long_text\",\"data\":[[\"2\",\"test\",\"{\"link\":\"\",\"title\":\"` + shortText + `\"}\",\"{\"link\":\"` + linkLongText + `\",\"title\":\"` + longText[:32] + `\"}\"]],\"name\":\"` + name + `\",\"source\":\"mysrc\",\"types\":[\"text\",\"text\",\"long_text\",\"long_text\"],\"whereid\":\"2\"}}]`\n\tif RawToString(ret.Tree) != want {\n\t\tt.Errorf(\"Wrong image tree %s != %s\", RawToString(ret.Tree), want)\n\t}\n\n\tresp, err := http.Get(apiAddress + consts.ApiPath + linkLongText)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tdefer resp.Body.Close()\n\n\tdata, err := io.ReadAll(resp.Body)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"attachment\", resp.Header.Get(\"Content-Disposition\"))\n\tassert.Equal(t, longText, string(data))\n}\n\nvar imageData = `iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAACXBIWXMAAAsTAAALEwEAmpwYAAAARklEQVRYw+3OMQ0AIBAEwQOzaCLBBQZfAd0XFLMCNjOyb1o7q2Ey82VYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYrwqjmwKzLUjCbwAAAABJRU5ErkJggg==`\n\nfunc TestBinary(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tdata, err := base64.StdEncoding.DecodeString(imageData)\n\tassert.NoError(t, err)\n\n\tfile := types.NewFile()\n\tfile.Set(\"Body\", data)\n\n\tparams := contractParams{\n\t\t\"ApplicationId\": \"1\",\n\t\t\"Name\":          \"file\",\n\t\t\"Data\":          file,\n\t}\n\n\t_, id, err := postTxResult(\"UploadFile\", &params)\n\tassert.NoError(t, err)\n\n\thash := crypto.Hash(data)\n\tassert.NoError(t, err)\n\thashImage := fmt.Sprintf(\"%x\", hash)\n\thashFindedImage := fmt.Sprintf(\"%x\", md5.Sum(data))\n\n\tcases := []struct {\n\t\tsource string\n\t\tresult string\n\t}{\n\t\t{\n\t\t\t`Image(Src: Binary(Name: file, AppID: 1, Account: #account_id#))`,\n\t\t\t`\\[{\"tag\":\"image\",\"attr\":{\"src\":\"/data/1_binaries/\\d+/data/` + hashImage + `\"}}\\]`,\n\t\t},\n\t\t{\n\t\t\t`Image(Src: Binary().ById(` + id + `)`,\n\t\t\t`\\[{\"tag\":\"image\",\"attr\":{\"src\":\"/data/1_binaries/\\d+/data/` + hashImage + `\"}}\\]`,\n\t\t},\n\t\t{\n\t\t\t`SetVar(eco, 1)Image(Src: Binary().ById(` + id + `).Ecosystem(#eco#)`,\n\t\t\t`\\[{\"tag\":\"image\",\"attr\":{\"src\":\"/data/1_binaries/\\d+/data/` + hashImage + `\"}}\\]`,\n\t\t},\n\t\t{\n\t\t\t`SetVar(name, file)SetVar(app_id, 1)SetVar(member_id, #key_id#)Image(Src: Binary(Name: #name#, AppID: #app_id#, MemberID: #member_id#))`,\n\t\t\t`\\[{\"tag\":\"image\",\"attr\":{\"src\":\"/data/1_binaries/\\d+/data/` + hashImage + `\"}}\\]`,\n\t\t},\n\t\t{\n\t\t\t`SetVar(id, \"` + id + `\")Image(Src: Binary().ById(#id#)`,\n\t\t\t`\\[{\"tag\":\"image\",\"attr\":{\"src\":\"/data/1_binaries/\\d+/data/` + hashImage + `\"}}\\]`,\n\t\t},\n\t\t{\n\t\t\t`DBFind(Name: binaries, Src: mysrc).Where({app_id: 1, account: #account_id#, name: \"file\"}).Custom(img){Image(Src: #data#)}Table(mysrc, \"Image=img\")`,\n\t\t\t`\\[{\"tag\":\"dbfind\",\"attr\":{\"columns\":\\[\"id\",\"app_id\",\"account\",\"name\",\"data\",\"hash\",\"mime_type\",\"img\"\\],\"data\":\\[\\[\"\\d+\",\"1\",\"\\d+\",\"file\",\"{\\\\\"link\\\\\":\\\\\"/data/1_binaries/\\d+/data/` + hashFindedImage + `\\\\\",\\\\\"title\\\\\":\\\\\"` + hashFindedImage + `\\\\\"}\",\"` + hashFindedImage + `\",\"application/octet-stream\",\"\\[{\\\\\"tag\\\\\":\\\\\"image\\\\\",\\\\\"attr\\\\\":{\\\\\"src\\\\\":\\\\\"/data/1_binaries/\\d+/data/` + hashFindedImage + `\\\\\"}}\\]\"\\]\\],\"name\":\"binaries\",\"source\":\"Src: mysrc\",\"types\":\\[\"text\",\"text\",\"text\",\"text\",\"blob\",\"text\",\"text\",\"tags\"\\],\"where\":\"app_id=1 AND member_id = \\d+ AND name = 'file'\"}},{\"tag\":\"table\",\"attr\":{\"columns\":\\[{\"Name\":\"img\",\"Title\":\"Image\"}\\],\"source\":\"mysrc\"}}\\]`,\n\t\t},\n\t\t{\n\t\t\t`DBFind(Name: binaries, Src: mysrc).Where({app_id: 1, account: #account_id#, name: \"file\"}).Vars(prefix)Image(Src: \"#prefix_data#\")`,\n\t\t\t`\\[{\"tag\":\"dbfind\",\"attr\":{\"columns\":\\[\"id\",\"app_id\",\"account\",\"name\",\"data\",\"hash\",\"mime_type\"\\],\"data\":\\[\\[\"\\d+\",\"1\",\"\\d+\",\"file\",\"{\\\\\"link\\\\\":\\\\\"/data/1_binaries/\\d+/data/` + hashFindedImage + `\\\\\",\\\\\"title\\\\\":\\\\\"` + hashFindedImage + `\\\\\"}\",\"` + hashFindedImage + `\",\"application/octet-stream\"\\]\\],\"name\":\"binaries\",\"source\":\"Src: mysrc\",\"types\":\\[\"text\",\"text\",\"text\",\"text\",\"blob\",\"text\",\"text\"\\],\"where\":\"app_id=1 AND member_id = \\d+ AND name = 'file'\"}},{\"tag\":\"image\",\"attr\":{\"src\":\"{\\\\\"link\\\\\":\\\\\"/data/1_binaries/\\d+/data/` + hashFindedImage + `\\\\\",\\\\\"title\\\\\":\\\\\"` + hashFindedImage + `\\\\\"}\"}}\\]`,\n\t\t},\n\t}\n\n\tfor _, v := range cases {\n\t\tvar ret contentResult\n\t\terr := sendPost(`content`, &url.Values{`template`: {v.source}}, &ret)\n\t\tassert.NoError(t, err)\n\t\tfmt.Println(v.result)\n\t\tassert.Regexp(t, v.result, string(ret.Tree))\n\t}\n}\n\nfunc TestStringToBinary(t *testing.T) {\n\tassert.NoError(t, keyLogin(1))\n\n\tcontract := randName(\"binary\")\n\tcontent := randName(\"content\")\n\tfilename := randName(\"file\")\n\tmimeType := \"text/plain\"\n\n\tform := url.Values{\n\t\t\"Value\": {`\n\t\t\tcontract ` + contract + ` {\n\t\t\t\tdata {\n\t\t\t\t\tContent string\n\t\t\t\t}\n\t\t\t\tconditions {}\n\t\t\t\taction {\n\t\t\t\t\tUploadBinary(\"Name,ApplicationId,Data,DataMimeType\", \"` + filename + `\", 1, StringToBytes($Content), \"text/plain\")\n\t\t\t\t\t$result = $account_id\n\t\t\t\t}\n\t\t\t}\n\t\t`}, \"ApplicationId\": {`1`}, \"Conditions\": {\"true\"},\n\t}\n\tassert.NoError(t, postTx(\"NewContract\", &form))\n\n\tform = url.Values{\"Content\": {content}}\n\t_, account, err := postTxResult(contract, &form)\n\tassert.NoError(t, err)\n\n\tform = url.Values{\n\t\t\"template\": {`SetVar(link, Binary(Name: ` + filename + `, AppID: 1, Account: \"` + account + `\"))#link#`},\n\t}\n\n\tvar ret struct {\n\t\tTree []struct {\n\t\t\tLink string `json:\"text\"`\n\t\t} `json:\"tree\"`\n\t}\n\tassert.NoError(t, sendPost(`content`, &form, &ret))\n\n\tresp, err := http.Get(apiAddress + consts.ApiPath + ret.Tree[0].Link)\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\tdefer resp.Body.Close()\n\tdata, err := io.ReadAll(resp.Body)\n\n\tassert.NoError(t, err)\n\tassert.Equal(t, content, string(data))\n\tassert.Equal(t, mimeType, resp.Header.Get(\"Content-Type\"))\n\tassert.Equal(t, `attachment; filename=\"`+filename+`\"`, resp.Header.Get(\"Content-Disposition\"))\n}\n"
  },
  {
    "path": "packages/api/trash.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n)\n\nfunc getContract(r *http.Request, name string) *smart.Contract {\n\tvm := script.GetVM()\n\tif vm == nil {\n\t\treturn nil\n\t}\n\tclient := getClient(r)\n\tcontract := smart.VMGetContract(vm, name, uint32(client.EcosystemID))\n\tif contract == nil {\n\t\treturn nil\n\t}\n\treturn contract\n}\n\nfunc getContractInfo(contract *smart.Contract) *script.ContractInfo {\n\treturn contract.Info()\n}\n"
  },
  {
    "path": "packages/api/tx_record.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n)\n\nfunc getTxRecord(w http.ResponseWriter, r *http.Request) {\n\tparams := mux.Vars(r)\n\thashes := params[\"hashes\"]\n\n\tvar (\n\t\thashList   []string\n\t\tresultList []any\n\t)\n\tif len(hashes) > 0 {\n\t\thashList = strings.Split(hashes, \",\")\n\t}\n\tfor _, hashStr := range hashList {\n\n\t\tif result, err := sqldb.GetTxRecord(nil, hashStr); err == nil {\n\t\t\tresultList = append(resultList, result)\n\t\t}\n\t}\n\tjsonResponse(w, &resultList)\n\treturn\n}\n"
  },
  {
    "path": "packages/api/txinfo.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/common\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/gorilla/mux\"\n)\n\ntype txinfoResult struct {\n\tBlockID string        `json:\"blockid\"`\n\tConfirm int           `json:\"confirm\"`\n\tData    *smart.TxInfo `json:\"data,omitempty\"`\n}\n\ntype txInfoForm struct {\n\tnopeValidator\n\tContractInfo bool   `schema:\"contractinfo\"`\n\tData         string `schema:\"data\"`\n}\n\ntype multiTxInfoResult struct {\n\tResults map[string]*txinfoResult `json:\"results\"`\n}\n\nfunc getTxInfo(r *http.Request, txHash string, getInfo bool) (*txinfoResult, error) {\n\tvar status txinfoResult\n\thash, err := hex.DecodeString(txHash)\n\tif err != nil {\n\t\treturn nil, errHashWrong\n\t}\n\tltx := &sqldb.LogTransaction{Hash: hash}\n\tfound, err := ltx.GetByHash(nil, hash)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !found {\n\t\treturn &status, nil\n\t}\n\tstatus.BlockID = converter.Int64ToStr(ltx.Block)\n\tvar confirm sqldb.Confirmation\n\tfound, err = confirm.GetConfirmation(ltx.Block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif found {\n\t\tstatus.Confirm = int(confirm.Good)\n\t}\n\tif getInfo {\n\t\tstatus.Data, err = transactionData(ltx.Block, hex.EncodeToString(ltx.Hash))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tstatus.Data.Status = ltx.Status\n\t\tstatus.Data.Ecosystem = ltx.EcosystemID\n\t}\n\n\treturn &status, nil\n}\n\nfunc getTxInfoHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &txInfoForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tparams := mux.Vars(r)\n\tstatus, err := getTxInfo(r, params[\"hash\"], form.ContractInfo)\n\tif err != nil {\n\t\terrorResponse(w, err)\n\t\treturn\n\t}\n\n\tjsonResponse(w, status)\n}\n\nfunc getTxInfoMultiHandler(w http.ResponseWriter, r *http.Request) {\n\tform := &txInfoForm{}\n\tif err := parseForm(r, form); err != nil {\n\t\terrorResponse(w, err, http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tresult := &multiTxInfoResult{}\n\tresult.Results = map[string]*txinfoResult{}\n\thashes := strings.Split(form.Data, \",\")\n\tfor _, hash := range hashes {\n\t\tstatus, err := getTxInfo(r, hash, form.ContractInfo)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tresult.Results[hash] = status\n\t}\n\n\tjsonResponse(w, result)\n}\n\nfunc transactionData(blockId int64, txHash string) (*smart.TxInfo, error) {\n\tinfo := &smart.TxInfo{}\n\tbk := &sqldb.BlockChain{}\n\tf, err := bk.Get(blockId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !f {\n\t\treturn nil, errors.New(\"not found\")\n\t}\n\n\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(bk.Data), false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, tx := range blck.Transactions {\n\t\thashStr := hex.EncodeToString(tx.Hash())\n\t\t//find next\n\t\tif hashStr != txHash {\n\t\t\tcontinue\n\t\t}\n\t\tinfo.Address = converter.AddressToString(tx.KeyID())\n\t\tinfo.Hash = hashStr\n\t\tinfo.Size = common.StorageSize(len(tx.Payload())).TerminalString()\n\t\tinfo.CreatedAt = tx.Timestamp()\n\n\t\tif tx.IsSmartContract() {\n\t\t\tinfo.Expedite = tx.SmartContract().TxSmart.Expedite\n\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\tinfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t}\n\t\t\tinfo.Params = tx.SmartContract().TxData\n\t\t\tif tx.Type() == types.TransferSelfTxType {\n\t\t\t\tinfo.Params = make(map[string]any)\n\t\t\t\tinfo.Params[\"transferSelf\"] = tx.SmartContract().TxSmart.TransferSelf\n\t\t\t}\n\t\t\tif tx.Type() == types.UtxoTxType {\n\t\t\t\tinfo.Params = make(map[string]any)\n\t\t\t\tinfo.Params[\"utxo\"] = tx.SmartContract().TxSmart.UTXO\n\t\t\t}\n\t\t}\n\t\t//find out break\n\t\tbreak\n\n\t}\n\tinfo.BlockId = blck.Header.BlockId\n\tinfo.BlockHash = hex.EncodeToString(blck.Header.BlockHash)\n\n\treturn info, nil\n}\n"
  },
  {
    "path": "packages/api/txstatus.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype txstatusError struct {\n\tType  string `json:\"type,omitempty\"`\n\tError string `json:\"error,omitempty\"`\n\tId    string `json:\"id,omitempty\"`\n}\n\ntype txstatusResult struct {\n\tBlockID string         `json:\"blockid\"`\n\tMessage *txstatusError `json:\"errmsg,omitempty\"`\n\tResult  string         `json:\"result\"`\n\tPenalty int64          `json:\"penalty\"`\n}\n\nfunc getTxStatus(r *http.Request, hash string) (*txstatusResult, error) {\n\tlogger := getLogger(r)\n\n\tvar status txstatusResult\n\tif _, err := hex.DecodeString(hash); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"decoding tx hash from hex\")\n\t\treturn nil, errHashWrong\n\t}\n\tts := &sqldb.TransactionStatus{}\n\tfound, err := ts.Get([]byte(converter.HexToBin(hash)))\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"getting transaction status by hash\")\n\t\treturn nil, err\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"key\": []byte(converter.HexToBin(hash))}).Debug(\"getting transaction status by hash\")\n\t\treturn nil, errHashNotFound.Errorf(hash)\n\t}\n\tcheckErr := func() {\n\t\tif len(ts.Error) > 0 {\n\t\t\tif err := json.Unmarshal([]byte(ts.Error), &status.Message); err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"text\": ts.Error, \"error\": err}).Warn(\"unmarshalling txstatus error\")\n\t\t\t\tstatus.Message = &txstatusError{\n\t\t\t\t\tType:  \"txError\",\n\t\t\t\t\tError: ts.Error,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif ts.BlockID > 0 {\n\t\tstatus.BlockID = converter.Int64ToStr(ts.BlockID)\n\t\tstatus.Penalty = ts.Penalty\n\t\tif ts.Penalty == 1 {\n\t\t\tcheckErr()\n\t\t} else {\n\t\t\tstatus.Result = ts.Error\n\t\t}\n\t} else {\n\t\tcheckErr()\n\t}\n\treturn &status, nil\n}\n\ntype multiTxStatusResult struct {\n\tResults map[string]*txstatusResult `json:\"results\"`\n}\n\ntype txstatusRequest struct {\n\tHashes []string `json:\"hashes\"`\n}\n\nfunc getTxStatusHandler(w http.ResponseWriter, r *http.Request) {\n\tresult := &multiTxStatusResult{}\n\tresult.Results = map[string]*txstatusResult{}\n\n\tvar request txstatusRequest\n\tif err := json.Unmarshal([]byte(r.FormValue(\"data\")), &request); err != nil {\n\t\terrorResponse(w, errHashWrong)\n\t\treturn\n\t}\n\tfor _, hash := range request.Hashes {\n\t\tstatus, err := getTxStatus(r, hash)\n\t\tif err != nil {\n\t\t\terrorResponse(w, err)\n\t\t\treturn\n\t\t}\n\t\tresult.Results[hash] = status\n\t}\n\n\tjsonResponse(w, result)\n}\n"
  },
  {
    "path": "packages/api/version.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage api\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n)\n\nfunc getVersionHandler(w http.ResponseWriter, r *http.Request) {\n\tjsonResponse(w, consts.Version()+\" \"+node.NodePauseType().String())\n}\n"
  },
  {
    "path": "packages/block/block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage block\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar (\n\tErrIncorrectRollbackHash = errors.New(\"Rollback hash doesn't match\")\n\tErrEmptyBlock            = errors.New(\"Block doesn't contain transactions\")\n\tErrIncorrectBlockTime    = utils.WithBan(errors.New(\"Incorrect block time\"))\n)\n\n// Block is storing block data\ntype Block struct {\n\t*types.BlockData\n\tPrevRollbacksHash []byte\n\tTransactions      []*transaction.Transaction\n\tGenBlock          bool // it equals true when we are generating a new block\n\tNotifications     []types.Notifications\n\tOutputsMap        map[sqldb.KeyUTXO][]sqldb.SpentInfo\n\tClassifyTxsMap    map[int][]*transaction.Transaction\n\tPrevSysPar        map[string]string\n\tEcoParams         []sqldb.EcoParam // combustion percent,digits for each ecosystem\n}\n\n// GetLogger is returns logger\nfunc (b *Block) GetLogger() *log.Entry {\n\treturn log.WithFields(log.Fields{\"block_id\": b.Header.BlockId, \"block_time\": b.Header.Timestamp, \"block_wallet_id\": b.Header.KeyId,\n\t\t\"block_state_id\": b.Header.EcosystemId, \"block_hash\": b.Header.BlockHash, \"block_version\": b.Header.Version})\n}\n\nfunc (b *Block) IsGenesis() bool {\n\treturn b.Header.BlockId == 1\n}\n\nfunc (b *Block) limitMode() transaction.LimitMode {\n\tif b == nil {\n\t\treturn transaction.GetLetPreprocess()\n\t}\n\tif b.GenBlock {\n\t\treturn transaction.GetLetGenBlock()\n\t}\n\treturn transaction.GetLetParsing()\n}\n\n// InsertBlockWOForks is inserting blocks\nfunc InsertBlockWOForksNew(data []byte, classifyTxsMap map[int][]*transaction.Transaction, genBlock, firstBlock bool) error {\n\tblock, err := ProcessBlockByBinData(data, !firstBlock)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tblock.GenBlock = genBlock\n\tif !firstBlock {\n\t\tblock.ClassifyTxsMap = classifyTxsMap\n\t}\n\tif err := block.Check(); err != nil {\n\t\treturn err\n\t}\n\n\terr = block.PlaySafe()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.WithFields(log.Fields{\"block_id\": block.Header.BlockId}).Debug(\"block was inserted successfully\")\n\treturn nil\n}\n"
  },
  {
    "path": "packages/block/check.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/protocols\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Check is checking block\nfunc (b *Block) Check() error {\n\t// skip validation for first block\n\tif b.IsGenesis() {\n\t\treturn nil\n\t}\n\tlogger := b.GetLogger()\n\tif b.PrevHeader.BlockId != b.Header.BlockId-1 {\n\t\tvar err error\n\t\tb.PrevHeader, err = GetBlockHeaderFromBlockChain(b.Header.BlockId - 1)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.InvalidObject}).Error(\"block id is larger then previous more than on 1\")\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif b.Header.Timestamp > time.Now().Unix() {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ParameterExceeded}).Error(\"block time is larger than now\")\n\t\treturn ErrIncorrectBlockTime\n\t}\n\tvar (\n\t\texists bool\n\t\terr    error\n\t)\n\tif syspar.IsHonorNodeMode() {\n\t\t// is this block too early? Allowable error = error_time\n\t\texists, err = protocols.NewBlockTimeCounter().BlockForTimeExists(time.Unix(b.Header.Timestamp, 0), int(b.Header.NodePosition))\n\t}\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Error(\"calculating block time\")\n\t\treturn err\n\t}\n\n\tif exists {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Warn(\"incorrect block time\")\n\t\treturn utils.WithBan(fmt.Errorf(\"%s %d\", ErrIncorrectBlockTime, b.PrevHeader.Timestamp))\n\t}\n\tif !bytes.Equal(b.PrevRollbacksHash, b.PrevHeader.RollbacksHash) {\n\t\treturn ErrIncorrectRollbackHash\n\t}\n\t// check each transaction\n\ttxCounter := make(map[int64]int)\n\ttxHashes := make(map[string]struct{})\n\tfor i, t := range b.Transactions {\n\t\thexHash := string(converter.BinToHex(t.Hash()))\n\t\t// check for duplicate transactions\n\t\tif _, ok := txHashes[hexHash]; ok {\n\t\t\tlogger.WithFields(log.Fields{\"tx_hash\": hexHash, \"type\": consts.DuplicateObject}).Warning(\"duplicate transaction\")\n\t\t\treturn utils.ErrInfo(fmt.Errorf(\"duplicate transaction %s\", hexHash))\n\t\t}\n\t\ttxHashes[hexHash] = struct{}{}\n\n\t\t// check for max transaction per user in one block\n\t\ttxCounter[t.KeyID()]++\n\t\tif txCounter[t.KeyID()] > syspar.GetMaxBlockUserTx() {\n\t\t\treturn utils.WithBan(utils.ErrInfo(fmt.Errorf(\"max_block_user_transactions\")))\n\t\t}\n\n\t\terr := t.Check(b.Header.Timestamp)\n\t\tif err != nil {\n\t\t\ttransaction.MarkTransactionBad(t.Hash(), err.Error())\n\t\t\tdelete(txHashes, hexHash)\n\t\t\tb.Transactions = append(b.Transactions[:i], b.Transactions[i+1:]...)\n\t\t\treturn errors.Wrap(err, \"check transaction\")\n\t\t}\n\t}\n\n\t// hash compare could be failed in the case of fork\n\terr = b.CheckSign()\n\tif err != nil {\n\t\ttransaction.CleanCache()\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (b *Block) CheckSign() error {\n\tif b.IsGenesis() || conf.Config.IsSubNode() || b.PrevHeader == nil {\n\t\treturn nil\n\t}\n\tnodePub, err := syspar.GetNodePublicKeyByPosition(b.Header.NodePosition)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%v: %w\", fmt.Sprintf(\"get node public key by position '%d'\", b.Header.NodePosition), err)\n\t}\n\tif len(nodePub) == 0 {\n\t\treturn fmt.Errorf(\"empty nodePublicKey\")\n\t}\n\t_, err = utils.CheckSign([][]byte{nodePub}, []byte(b.ForSign()), b.Header.Sign, true)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"checking block header sign\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/block/db.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/protocols\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"gorm.io/gorm\"\n)\n\n// ProcessBlockByBinData is processing block with in table previous block\nfunc ProcessBlockByBinData(data []byte, checkSize bool) (*Block, error) {\n\tif checkSize && int64(len(data)) > syspar.GetMaxBlockSize() {\n\t\tlog.WithFields(log.Fields{\"check_size\": checkSize, \"size\": len(data), \"max_size\": syspar.GetMaxBlockSize(), \"type\": consts.ParameterExceeded}).Error(\"binary block size exceeds max block size\")\n\t\treturn nil, types.ErrMaxBlockSize(syspar.GetMaxBlockSize(), len(data))\n\t}\n\tblock, err := UnmarshallBlock(bytes.NewBuffer(data), true)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(types.ErrUnmarshallBlock, err.Error())\n\t}\n\tblock.PrevHeader, err = GetBlockHeaderFromBlockChain(block.Header.BlockId - 1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif block.PrevHeader == nil {\n\t\treturn nil, errors.New(\"block previous header nil\")\n\t}\n\treturn block, nil\n}\n\nfunc (b *Block) GetRollbacksHash(dbTx *sqldb.DbTransaction) ([]byte, error) {\n\tr := &sqldb.RollbackTx{}\n\tdiff, err := r.GetRollbacksDiff(dbTx, b.Header.BlockId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn crypto.Hash(diff), nil\n}\n\nfunc GetRollbacksHashWithDiffArr(dbTx *sqldb.DbTransaction, bId int64) ([]byte, error) {\n\trollbackTx := sqldb.RollbackTx{}\n\trollbackTxs, err := rollbackTx.GetBlockRollbackTransactions(dbTx, bId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tarr := make([]string, 0)\n\tfor _, row := range rollbackTxs {\n\t\tdata, err := json.Marshal(row)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tarr = append(arr, crypto.HashHex(data))\n\t}\n\tspentInfos, err := sqldb.GetBlockOutputs(dbTx, bId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, row := range spentInfos {\n\t\tdata, err := json.Marshal(row)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tarr = append(arr, crypto.HashHex(data))\n\t}\n\tsort.Strings(arr)\n\tmarshal, _ := json.Marshal(arr)\n\treturn crypto.Hash(marshal), nil\n}\n\n// InsertIntoBlockchain inserts a block into the blockchain\nfunc (b *Block) InsertIntoBlockchain(dbTx *sqldb.DbTransaction) error {\n\tblockID := b.Header.BlockId\n\tbl := &sqldb.BlockChain{}\n\terr := bl.DeleteById(dbTx, blockID)\n\tif err != nil {\n\t\tb.GetLogger().WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting block by id\")\n\t\treturn err\n\t}\n\tvar rHash []byte\n\trHash, err = GetRollbacksHashWithDiffArr(dbTx, blockID)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Error(\"getting rollbacks hash\")\n\t\treturn err\n\t}\n\tif b.GenBlock {\n\t\tb.Header.RollbacksHash = rHash\n\t\tif err = b.repeatMarshallBlock(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tblockchain := &sqldb.BlockChain{\n\t\tID:             blockID,\n\t\tHash:           b.Header.BlockHash,\n\t\tData:           b.BinData,\n\t\tEcosystemID:    b.Header.EcosystemId,\n\t\tKeyID:          b.Header.KeyId,\n\t\tNodePosition:   b.Header.NodePosition,\n\t\tTime:           b.Header.Timestamp,\n\t\tRollbacksHash:  rHash,\n\t\tTx:             int32(len(b.TxFullData)),\n\t\tConsensusMode:  b.Header.ConsensusMode,\n\t\tCandidateNodes: b.Header.CandidateNodes,\n\t}\n\tvar validBlockTime bool\n\tif blockID > 1 && syspar.IsHonorNodeMode() {\n\t\tvalidBlockTime, err = protocols.NewBlockTimeCounter().BlockForTimeExists(time.Unix(blockchain.Time, 0), int(blockchain.NodePosition))\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Error(\"block validation\")\n\t\t\treturn err\n\t\t}\n\t\tif validBlockTime {\n\t\t\terr = fmt.Errorf(\"invalid block time: %d\", b.Header.Timestamp)\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Error(\"invalid block time\")\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err = blockchain.Create(dbTx); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating block\")\n\t\treturn err\n\t}\n\tif err := b.upsertInfoBlock(dbTx, blockchain); err != nil {\n\t\treturn err\n\t}\n\tif b.SysUpdate {\n\t\tb.SysUpdate = false\n\t\tif err := syspar.SysUpdate(dbTx); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating syspar\")\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// GetBlockHeaderFromBlockChain is retrieving block data from blockchain\nfunc GetBlockHeaderFromBlockChain(blockID int64) (*types.BlockHeader, error) {\n\tif blockID < 1 {\n\t\treturn &types.BlockHeader{}, nil\n\t}\n\tblock := new(sqldb.BlockChain)\n\tif _, err := block.Get(blockID); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"find block by ID %d\", blockID)\n\t}\n\n\theader, err := types.ParseBlockHeader(bytes.NewBuffer(block.Data), syspar.GetMaxBlockSize())\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"parse block header by ID %d\", blockID)\n\t}\n\theader.BlockHash = block.Hash\n\theader.RollbacksHash = block.RollbacksHash\n\treturn header, nil\n}\n\n// GetDataFromFirstBlock returns data of first block\nfunc GetDataFromFirstBlock() (data *types.FirstBlock, ok bool) {\n\tblock := &sqldb.BlockChain{}\n\tisFound, err := block.Get(1)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting record of first block\")\n\t\treturn\n\t}\n\n\tif !isFound {\n\t\treturn\n\t}\n\n\tpb, err := UnmarshallBlock(bytes.NewBuffer(block.Data), true)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParserError, \"error\": err}).Error(\"parsing data of first block\")\n\t\treturn\n\t}\n\n\tif len(pb.Transactions) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParserError}).Error(\"list of parsers is empty\")\n\t\treturn\n\t}\n\n\tt := pb.Transactions[0]\n\ttx, ok := t.Inner.(*transaction.FirstBlockParser)\n\tif !ok {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParserError}).Error(\"getting data of first block\")\n\t\treturn\n\t}\n\tdata = tx.Data\n\tsyspar.SetFirstBlockTimestamp(time.UnixMilli(tx.Timestamp).Unix())\n\tsyspar.SysUpdate(nil)\n\treturn\n}\n\n// upsertInfoBlock updates info_block table\nfunc (b *Block) upsertInfoBlock(dbTx *sqldb.DbTransaction, block *sqldb.BlockChain) error {\n\tib := &sqldb.InfoBlock{\n\t\tHash:           block.Hash,\n\t\tBlockID:        block.ID,\n\t\tTime:           block.Time,\n\t\tEcosystemID:    block.EcosystemID,\n\t\tKeyID:          block.KeyID,\n\t\tNodePosition:   converter.Int64ToStr(block.NodePosition),\n\t\tRollbacksHash:  block.RollbacksHash,\n\t\tConsensusMode:  block.ConsensusMode,\n\t\tCandidateNodes: block.CandidateNodes,\n\t}\n\tif block.ID == 1 {\n\t\tib.CurrentVersion = fmt.Sprintf(\"%d\", consts.BlockVersion)\n\t\terr := ib.Create(dbTx)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating info block\")\n\t\t\treturn fmt.Errorf(\"error insert into info_block %s\", err)\n\t\t}\n\t} else {\n\t\tib.Sent = 0\n\t\tif err := ib.Update(dbTx); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating info block\")\n\t\t\treturn fmt.Errorf(\"error while updating info_block %s\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype AfterTxs struct {\n\tUsedTx      [][]byte\n\tRts         []*sqldb.RollbackTx\n\tLts         []*sqldb.LogTransaction\n\tUpdTxStatus []*pbgo.TxResult\n}\n\nfunc (b *Block) GenAfterTxs() *AfterTxs {\n\tafter := b.AfterTxs\n\tplayTx := &AfterTxs{\n\t\tRts:         make([]*sqldb.RollbackTx, len(after.Rts)),\n\t\tLts:         make([]*sqldb.LogTransaction, len(after.Txs)),\n\t\tUpdTxStatus: make([]*pbgo.TxResult, len(after.Txs)),\n\t}\n\n\tfor i := 0; i < len(after.Rts); i++ {\n\t\ttx := after.Rts[i]\n\t\trt := new(sqldb.RollbackTx)\n\t\trt.BlockID = tx.BlockId\n\t\trt.NameTable = tx.NameTable\n\t\trt.Data = tx.Data\n\t\trt.TableID = tx.TableId\n\t\trt.TxHash = tx.TxHash\n\t\trt.DataHash = tx.DataHash\n\t\tplayTx.Rts[i] = rt\n\t}\n\n\tfor i := 0; i < len(after.Txs); i++ {\n\t\ttx := after.Txs[i]\n\t\tplayTx.UsedTx = append(playTx.UsedTx, tx.UsedTx)\n\t\tlt := new(sqldb.LogTransaction)\n\t\tlt.Block = tx.Lts.Block\n\t\tlt.Hash = tx.Lts.Hash\n\t\t//lt.TxData = tx.Lts.TxData\n\t\tlt.Timestamp = tx.Lts.Timestamp\n\t\tlt.Address = tx.Lts.Address\n\t\tlt.EcosystemID = tx.Lts.EcosystemId\n\t\tlt.ContractName = tx.Lts.ContractName\n\t\tlt.Status = int64(tx.Lts.InvokeStatus)\n\t\tplayTx.Lts[i] = lt\n\n\t\tu := new(pbgo.TxResult)\n\t\tu = tx.UpdTxStatus\n\t\tplayTx.UpdTxStatus[i] = u\n\t}\n\treturn playTx\n}\n\nfunc (b *Block) AfterPlayTxs(dbTx *sqldb.DbTransaction) error {\n\tplayTx := b.GenAfterTxs()\n\treturn sqldb.GetDB(dbTx).Transaction(func(tx *gorm.DB) error {\n\t\t//if !b.GenBlock && !b.IsGenesis() && conf.Config.BlockSyncMethod.Method == types.BlockSyncMethod_SQLDML.String() {\n\t\t//\tfor i := 0; i < len(b.AfterTxs.TxBinLogSql); i++ {\n\t\t//\t\tif err := tx.Exec(string(b.AfterTxs.TxBinLogSql[i])).Error; err != nil {\n\t\t//\t\t\treturn errors.Wrap(err, \"batches exec sql for tx\")\n\t\t//\t\t}\n\t\t//\t}\n\t\t//}\n\t\tif err := sqldb.DeleteTransactions(tx, playTx.UsedTx); err != nil {\n\t\t\treturn errors.Wrap(err, \"batches delete used transactions\")\n\t\t}\n\t\tif err := sqldb.CreateLogTransactionBatches(tx, playTx.Lts); err != nil {\n\t\t\treturn errors.Wrap(err, \"batches insert log_transactions\")\n\t\t}\n\t\tspentInfos := sqldb.GetAllOutputs(b.OutputsMap)\n\t\tif len(spentInfos) > 0 {\n\t\t\tif err := sqldb.CreateSpentInfoBatches(tx, spentInfos); err != nil {\n\t\t\t\treturn errors.Wrap(err, \"batches insert spent_info\")\n\t\t\t}\n\t\t}\n\n\t\tif err := sqldb.CreateBatchesRollbackTx(tx, playTx.Rts); err != nil {\n\t\t\treturn errors.Wrap(err, \"batches insert rollback tx\")\n\t\t}\n\t\tif err := sqldb.UpdateBlockMsgBatches(tx, b.Header.BlockId, playTx.UpdTxStatus); err != nil {\n\t\t\treturn errors.Wrap(err, \"batches update block msg transaction status\")\n\t\t}\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "packages/block/play.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/random\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/notificator\"\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// PlaySafe is inserting block safely\nfunc (b *Block) PlaySafe() error {\n\tlogger := b.GetLogger()\n\tdbTx, err := sqldb.StartTransaction()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"starting db transaction\")\n\t\treturn err\n\t}\n\n\terr = b.ProcessTxs(dbTx)\n\tif err != nil {\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\n\tif b.GenBlock && len(b.TxFullData) == 0 {\n\t\tdbTx.Commit()\n\t\treturn ErrEmptyBlock\n\t}\n\n\tif err := b.InsertIntoBlockchain(dbTx); err != nil {\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\terr = dbTx.Commit()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, q := range b.Notifications {\n\t\tq.Send()\n\t}\n\treturn nil\n}\n\ntype badTxStruct struct {\n\tindex int\n\thash  []byte\n\tmsg   string\n\tkeyID int64\n}\n\nfunc (b *Block) ProcessTxs(dbTx *sqldb.DbTransaction) (err error) {\n\tafters := &types.AfterTxs{\n\t\tRts: make([]*types.RollbackTx, 0),\n\t\tTxs: make([]*types.AfterTx, 0),\n\t}\n\ttxsMap := b.ClassifyTxsMap\n\tprocessedTx := make([][]byte, 0, len(b.Transactions))\n\n\tprocessBadTx := func() chan badTxStruct {\n\t\tch := make(chan badTxStruct)\n\t\tgo func() {\n\t\t\tfor badTxItem := range ch {\n\t\t\t\ttransaction.BadTxForBan(badTxItem.keyID)\n\t\t\t\t_ = transaction.MarkTransactionBad(badTxItem.hash, badTxItem.msg)\n\t\t\t}\n\t\t}()\n\t\treturn ch\n\t}\n\n\ttxBadChan := processBadTx()\n\tdefer func() {\n\t\tclose(txBadChan)\n\t\tif b.IsGenesis() || b.GenBlock || b.AfterTxs != nil {\n\t\t\tb.AfterTxs = afters\n\t\t}\n\t\tif b.GenBlock {\n\t\t\tb.TxFullData = processedTx\n\t\t}\n\n\t\tif errA := b.AfterPlayTxs(dbTx); errA != nil {\n\t\t\tif err == nil {\n\t\t\t\terr = errA\n\t\t\t} else if err != nil {\n\t\t\t\terr = fmt.Errorf(\"%v; %w\", err, errA)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}()\n\t//if !b.GenBlock && !b.IsGenesis() && conf.Config.BlockSyncMethod.Method == types.BlockSyncMethod_SQLDML.String() {\n\t//\tif b.SysUpdate {\n\t//\t\tif err := syspar.SysUpdate(dbTx); err != nil {\n\t//\t\t\treturn fmt.Errorf(\"updating syspar: %w\", err)\n\t//\t\t}\n\t//\t}\n\t//\treturn nil\n\t//}\n\n\tvar keyIds []int64\n\tvar keyIdsMap = make(map[int64]bool)\n\tvar ecosystemIds []int64\n\tvar ecosystemIdsMap = make(map[int64]bool)\n\tfor indexTx := 0; indexTx < len(b.Transactions); indexTx++ {\n\t\tt := b.Transactions[indexTx]\n\t\tif !keyIdsMap[t.KeyID()] {\n\t\t\tkeyIdsMap[t.KeyID()] = true\n\t\t\tkeyIds = append(keyIds, t.KeyID())\n\t\t}\n\t\tif t.IsSmartContract() && !ecosystemIdsMap[t.SmartContract().TxSmart.EcosystemID] {\n\t\t\tecosystemIdsMap[t.SmartContract().TxSmart.EcosystemID] = true\n\t\t\tecosystemIds = append(ecosystemIds, t.SmartContract().TxSmart.EcosystemID)\n\t\t}\n\t}\n\t// query all keys utxo\n\toutputs, err := sqldb.GetTxOutputs(dbTx, keyIds)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.OutputsMap = make(map[sqldb.KeyUTXO][]sqldb.SpentInfo)\n\tsqldb.PutAllOutputsMap(outputs, b.OutputsMap)\n\t// query all ecosystems combination percent\n\tecoParams, err := sqldb.GetEcoParam(dbTx, ecosystemIds)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.EcoParams = ecoParams\n\t// UTXO multiple ecosystem fuelRate\n\tb.PrevSysPar = syspar.GetSysParCache()\n\tvar wg sync.WaitGroup\n\n\t// StopNetworkTxType\n\tif len(txsMap[types.StopNetworkTxType]) > 0 {\n\t\ttransactions := txsMap[types.StopNetworkTxType]\n\t\terr := b.serialExecuteTxs(dbTx, txBadChan, afters, &processedTx, transactions, lock)\n\t\tdelete(txsMap, types.StopNetworkTxType)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n\n\t// FirstBlockTxType\n\tif b.IsGenesis() {\n\t\ttransactions := make([]*transaction.Transaction, 0)\n\t\tfor _, tx := range b.Transactions {\n\t\t\tt, err := transaction.UnmarshallTransaction(bytes.NewBuffer(tx.FullData), false)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttransactions = append(transactions, t)\n\t\t}\n\t\terr := b.serialExecuteTxs(dbTx, txBadChan, afters, &processedTx, transactions, lock)\n\t\ttransactions = make([]*transaction.Transaction, 0)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// DelayTxType\n\tif len(txsMap[types.DelayTxType]) > 0 {\n\t\ttransactions := txsMap[types.DelayTxType]\n\t\terr := b.serialExecuteTxs(dbTx, txBadChan, afters, &processedTx, transactions, lock)\n\t\tdelete(txsMap, types.DelayTxType)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// TransferSelf\n\tif len(txsMap[types.TransferSelfTxType]) > 0 {\n\t\ttransactions := txsMap[types.TransferSelfTxType]\n\n\t\twalletAddress := make(map[int64]int64)\n\t\tgroupTransferSelfTxs(transactions, walletAddress)\n\t\tfor _, transactions := range transferSelfTxsGroupMap {\n\t\t\twg.Add(1)\n\t\t\tgo func(_dbTx *sqldb.DbTransaction, _txBadChan chan badTxStruct, _transactions []*transaction.Transaction, _afters *types.AfterTxs, _processedTx *[][]byte, _lock *sync.RWMutex) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\terr := b.serialExecuteTxs(_dbTx, _txBadChan, _afters, _processedTx, _transactions, _lock)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}(dbTx, txBadChan, transactions, afters, &processedTx, lock)\n\t\t}\n\t\twg.Wait()\n\t\ttransferSelfTxsGroupMap = make(map[string][]*transaction.Transaction, 0)\n\t\ttransferSelfGroupTxsList = make([]*transaction.Transaction, 0)\n\t\ttransferSelfGroupSerial = 1\n\t\tdelete(txsMap, types.TransferSelfTxType)\n\t}\n\n\t//Utxo && Smart contract\n\tif len(txsMap[types.UtxoTxType]) > 0 || len(txsMap[types.SmartContractTxType]) > 0 {\n\t\ttransactions := txsMap[types.UtxoTxType]\n\t\t// utxo group\n\t\twalletAddress := make(map[int64]int64)\n\t\tgroupUtxoTxs(transactions, walletAddress)\n\t\tif len(txsMap[types.SmartContractTxType]) > 0 {\n\t\t\tutxoTxsGroupMap[strconv.Itoa(0)] = txsMap[types.SmartContractTxType]\n\t\t}\n\t\tfor _, transactions := range utxoTxsGroupMap {\n\t\t\twg.Add(1)\n\t\t\tgo func(_dbTx *sqldb.DbTransaction, _txBadChan chan badTxStruct, _transactions []*transaction.Transaction, _afters *types.AfterTxs, _processedTx *[][]byte, _lock *sync.RWMutex) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\terr := b.serialExecuteTxs(_dbTx, _txBadChan, _afters, _processedTx, _transactions, _lock)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}(dbTx, txBadChan, transactions, afters, &processedTx, lock)\n\t\t}\n\t\twg.Wait()\n\t\tutxoTxsGroupMap = make(map[string][]*transaction.Transaction, 0)\n\t\tutxoGroupTxsList = make([]*transaction.Transaction, 0)\n\t\tutxoGroupSerial = 1\n\t\tdelete(txsMap, types.UtxoTxType)\n\t\tdelete(txsMap, types.SmartContractTxType)\n\t}\n\n\treturn nil\n}\n\nfunc (b *Block) serialExecuteTxs(dbTx *sqldb.DbTransaction, txBadChan chan badTxStruct, afters *types.AfterTxs, processedTx *[][]byte, txs []*transaction.Transaction, _lock *sync.RWMutex) error {\n\t_lock.Lock()\n\tdefer _lock.Unlock()\n\tlimits := transaction.NewLimits(b.limitMode())\n\trand := random.NewRand(b.Header.Timestamp)\n\tlogger := b.GetLogger()\n\tfor curTx := 0; curTx < len(txs); curTx++ {\n\t\tt := txs[curTx]\n\t\terr := dbTx.Savepoint(consts.SetSavePointMarkBlock(hex.EncodeToString(t.Hash())))\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"tx_hash\": t.Hash()}).Error(\"using savepoint\")\n\t\t\treturn err\n\t\t}\n\t\terr = t.WithOption(notificator.NewQueue(), b.GenBlock, b.Header, b.PrevHeader, dbTx, rand.BytesSeed(t.Hash()), limits,\n\t\t\tconsts.SetSavePointMarkBlock(hex.EncodeToString(t.Hash())), b.OutputsMap, b.PrevSysPar, b.EcoParams)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = t.Play()\n\t\tif err != nil {\n\t\t\tif err == transaction.ErrNetworkStopping {\n\t\t\t\t// Set the node in a pause state\n\t\t\t\tnode.PauseNodeActivity(node.PauseTypeStopingNetwork)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terrRoll := t.DbTransaction.RollbackSavepoint(consts.SetSavePointMarkBlock(hex.EncodeToString(t.Hash())))\n\t\t\tif errRoll != nil {\n\t\t\t\treturn fmt.Errorf(\"%v; %w\", err, errRoll)\n\t\t\t}\n\t\t\tif b.GenBlock {\n\t\t\t\tif errors.Cause(err) == transaction.ErrLimitStop {\n\t\t\t\t\tif curTx == 0 {\n\t\t\t\t\t\ttxBadChan <- badTxStruct{index: curTx, hash: t.Hash(), msg: err.Error(), keyID: t.KeyID()}\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\ttxBadChan <- badTxStruct{index: curTx, hash: t.Hash(), msg: err.Error(), keyID: t.KeyID()}\n\t\t\tif t.SysUpdate {\n\t\t\t\tif err := syspar.SysUpdate(t.DbTransaction); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"updating syspar: %w\", err)\n\t\t\t\t}\n\t\t\t\tt.SysUpdate = false\n\t\t\t}\n\t\t\tif b.GenBlock {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\n\t\tif t.SysUpdate {\n\t\t\tb.SysUpdate = true\n\t\t\tt.SysUpdate = false\n\t\t}\n\n\t\tif t.Notifications.Size() > 0 {\n\t\t\tb.Notifications = append(b.Notifications, t.Notifications)\n\t\t}\n\n\t\tvar (\n\t\t\tafter    = &types.AfterTx{}\n\t\t\teco      = int64(1)\n\t\t\tcontract string\n\t\t\tcode     pbgo.TxInvokeStatusCode\n\t\t)\n\t\tif t.IsSmartContract() {\n\t\t\teco = t.SmartContract().TxSmart.EcosystemID\n\t\t\tcode = t.TxResult.Code\n\t\t\tif t.SmartContract().TxContract != nil {\n\t\t\t\tcontract = t.SmartContract().TxContract.Name\n\t\t\t}\n\t\t}\n\t\tafter.UsedTx = t.Hash()\n\t\tafter.Lts = &types.LogTransaction{\n\t\t\tBlock: t.BlockHeader.BlockId,\n\t\t\tHash:  t.Hash(),\n\t\t\t//TxData:       t.FullData,\n\t\t\tTimestamp:    t.Timestamp(),\n\t\t\tAddress:      t.KeyID(),\n\t\t\tEcosystemId:  eco,\n\t\t\tContractName: contract,\n\t\t\tInvokeStatus: code,\n\t\t}\n\t\tafter.UpdTxStatus = t.TxResult\n\t\tafters.Txs = append(afters.Txs, after)\n\t\tafters.Rts = append(afters.Rts, t.RollBackTx...)\n\t\t//afters.TxBinLogSql = append(afters.TxBinLogSql, t.DbTransaction.BinLogSql...)\n\t\t*processedTx = append(*processedTx, t.FullData)\n\n\t\tsqldb.UpdateTxInputs(t.Hash(), t.TxInputsMap, b.OutputsMap)\n\t\tsqldb.InsertTxOutputs(t.Hash(), t.TxOutputsMap, b.OutputsMap)\n\t}\n\n\treturn nil\n}\n\nvar (\n\tutxoTxsGroupMap         = make(map[string][]*transaction.Transaction)\n\tutxoGroupTxsList        = make([]*transaction.Transaction, 0)\n\tutxoGroupSerial  uint16 = 1\n\tlock                    = &sync.RWMutex{}\n)\n\nfunc groupUtxoTxs(txs []*transaction.Transaction, walletAddress map[int64]int64) map[string][]*transaction.Transaction {\n\tif len(txs) == 0 {\n\t\treturn utxoTxsGroupMap\n\t}\n\tcrrentGroupTxsSize := len(utxoGroupTxsList)\n\tsize := len(txs)\n\tfor i := 0; i < size; i++ {\n\t\tif len(walletAddress) == 0 {\n\t\t\twalletAddress[txs[i].KeyID()] = txs[i].KeyID()\n\t\t\twalletAddress[txs[i].SmartContract().TxSmart.UTXO.ToID] = txs[i].SmartContract().TxSmart.UTXO.ToID\n\n\t\t\tutxoGroupTxsList = append(utxoGroupTxsList, txs[i])\n\t\t\ttxs = txs[1:]\n\t\t\tsize = len(txs)\n\t\t\ti--\n\t\t\tcontinue\n\t\t}\n\t\tif walletAddress[txs[i].KeyID()] != 0 || walletAddress[txs[i].SmartContract().TxSmart.UTXO.ToID] != 0 {\n\t\t\twalletAddress[txs[i].KeyID()] = txs[i].KeyID()\n\t\t\twalletAddress[txs[i].SmartContract().TxSmart.UTXO.ToID] = txs[i].SmartContract().TxSmart.UTXO.ToID\n\n\t\t\tutxoGroupTxsList = append(utxoGroupTxsList, txs[i])\n\t\t\ttxs = append(txs[:i], txs[i+1:]...)\n\t\t\tsize = len(txs)\n\t\t\ti--\n\t\t}\n\t}\n\n\tif crrentGroupTxsSize < len(utxoGroupTxsList) {\n\t\tif len(txs) == 0 {\n\t\t\tutxoTxsGroupMap[strconv.Itoa(int(utxoGroupSerial))] = utxoGroupTxsList\n\t\t\treturn utxoTxsGroupMap\n\t\t}\n\t\treturn groupUtxoTxs(txs, walletAddress)\n\t}\n\n\tif len(utxoGroupTxsList) > 0 {\n\t\ttempUtxoGroupTxsList := utxoGroupTxsList\n\t\tutxoTxsGroupMap[strconv.Itoa(int(utxoGroupSerial))] = tempUtxoGroupTxsList\n\t\tutxoGroupSerial++\n\t\tutxoGroupTxsList = make([]*transaction.Transaction, 0)\n\t\twalletAddress = make(map[int64]int64)\n\t}\n\n\treturn groupUtxoTxs(txs, walletAddress)\n}\n\nvar (\n\ttransferSelfTxsGroupMap         = make(map[string][]*transaction.Transaction)\n\ttransferSelfGroupTxsList        = make([]*transaction.Transaction, 0)\n\ttransferSelfGroupSerial  uint16 = 1\n)\n\nfunc groupTransferSelfTxs(txs []*transaction.Transaction, walletAddress map[int64]int64) map[string][]*transaction.Transaction {\n\tif len(txs) == 0 {\n\t\treturn transferSelfTxsGroupMap\n\t}\n\tcrrentGroupTxsSize := len(transferSelfGroupTxsList)\n\tsize := len(txs)\n\tfor i := 0; i < size; i++ {\n\t\tif len(walletAddress) == 0 {\n\t\t\twalletAddress[txs[i].KeyID()] = txs[i].KeyID()\n\n\t\t\ttransferSelfGroupTxsList = append(transferSelfGroupTxsList, txs[i])\n\t\t\ttxs = txs[1:]\n\t\t\tsize = len(txs)\n\t\t\ti--\n\t\t\tcontinue\n\t\t}\n\t\tif walletAddress[txs[i].KeyID()] != 0 {\n\t\t\twalletAddress[txs[i].KeyID()] = txs[i].KeyID()\n\n\t\t\ttransferSelfGroupTxsList = append(transferSelfGroupTxsList, txs[i])\n\t\t\ttxs = append(txs[:i], txs[i+1:]...)\n\t\t\tsize = len(txs)\n\t\t\ti--\n\t\t}\n\t}\n\n\tif crrentGroupTxsSize < len(transferSelfGroupTxsList) {\n\t\tif len(txs) == 0 {\n\t\t\ttransferSelfTxsGroupMap[strconv.Itoa(int(transferSelfGroupSerial))] = transferSelfGroupTxsList\n\t\t\treturn transferSelfTxsGroupMap\n\t\t}\n\t\treturn groupTransferSelfTxs(txs, walletAddress)\n\t}\n\n\tif len(transferSelfGroupTxsList) > 0 {\n\t\ttempTransferSelfGroupTxsList := transferSelfGroupTxsList\n\t\ttransferSelfTxsGroupMap[strconv.Itoa(int(transferSelfGroupSerial))] = tempTransferSelfGroupTxsList\n\t\ttransferSelfGroupSerial++\n\t\ttransferSelfGroupTxsList = make([]*transaction.Transaction, 0)\n\t\twalletAddress = make(map[int64]int64)\n\t}\n\n\treturn groupTransferSelfTxs(txs, walletAddress)\n}\n"
  },
  {
    "path": "packages/block/serialization.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage block\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\nfunc (b *Block) repeatMarshallBlock() error {\n\tnewBlockData, err := MarshallBlock(\n\t\ttypes.WithCurHeader(b.Header),\n\t\ttypes.WithPrevHeader(b.PrevHeader),\n\t\ttypes.WithAfterTxs(b.AfterTxs),\n\t\ttypes.WithSysUpdate(b.SysUpdate),\n\t\ttypes.WithTxFullData(b.TxFullData))\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"marshalling repeat block\")\n\t}\n\n\tvar nb = new(Block)\n\tnb, err = UnmarshallBlock(bytes.NewBuffer(newBlockData), true)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"parsing repeat block\")\n\t}\n\tb.BinData = newBlockData\n\tb.Transactions = nb.Transactions\n\tb.MerkleRoot = nb.MerkleRoot\n\treturn nil\n}\n\nfunc MarshallBlock(opts ...types.BlockDataOption) ([]byte, error) {\n\tblock := &types.BlockData{}\n\tif err := block.Apply(opts...); err != nil {\n\t\treturn nil, err\n\t}\n\treturn block.MarshallBlock(syspar.GetNodePrivKey())\n}\n\nfunc UnmarshallBlock(blockBuffer *bytes.Buffer, fill bool) (*Block, error) {\n\tvar (\n\t\tcontractNames  []string\n\t\tclassifyTxsMap = make(map[int][]*transaction.Transaction)\n\t\tblock          = &types.BlockData{}\n\t)\n\tif err := block.UnmarshallBlock(blockBuffer.Bytes()); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif block.Header.BlockId != 1 {\n\t\tallDelayedContract, err := sqldb.GetAllDelayedContract()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfor _, contract := range allDelayedContract {\n\t\t\tcontractNames = append(contractNames, contract.Contract)\n\t\t}\n\t}\n\n\ttransactions := make([]*transaction.Transaction, 0)\n\tfor i := 0; i < len(block.TxFullData); i++ {\n\t\ttx, err := transaction.UnmarshallTransaction(bytes.NewBuffer(block.TxFullData[i]), fill)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif tx.Type() == types.StopNetworkTxType {\n\t\t\tclassifyTxsMap[types.StopNetworkTxType] = append(classifyTxsMap[types.StopNetworkTxType], tx)\n\t\t\ttransactions = append(transactions, tx)\n\t\t\tcontinue\n\t\t}\n\t\tif tx.IsSmartContract() {\n\t\t\tif tx.Type() == types.TransferSelfTxType {\n\t\t\t\tclassifyTxsMap[types.TransferSelfTxType] = append(classifyTxsMap[types.TransferSelfTxType], tx)\n\t\t\t\ttransactions = append(transactions, tx)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif tx.Type() == types.UtxoTxType {\n\t\t\t\tclassifyTxsMap[types.UtxoTxType] = append(classifyTxsMap[types.UtxoTxType], tx)\n\t\t\t\ttransactions = append(transactions, tx)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif utils.StringInSlice(contractNames, tx.SmartContract().TxContract.Name) {\n\t\t\t\tclassifyTxsMap[types.DelayTxType] = append(classifyTxsMap[types.DelayTxType], tx)\n\t\t\t\ttransactions = append(transactions, tx)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tclassifyTxsMap[types.SmartContractTxType] = append(classifyTxsMap[types.SmartContractTxType], tx)\n\t\t}\n\t\ttransactions = append(transactions, tx)\n\t}\n\n\treturn &Block{\n\t\tBlockData:         block,\n\t\tPrevRollbacksHash: block.PrevHeader.RollbacksHash,\n\t\tClassifyTxsMap:    classifyTxsMap,\n\t\tTransactions:      transactions,\n\t}, nil\n}\n"
  },
  {
    "path": "packages/chain/daemonsctl/daemonsctl.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemonsctl\n\nimport (\n\t\"context\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/modes\"\n)\n\n// RunAllDaemons start daemons, load contracts and tcpserver\nfunc RunAllDaemons(ctx context.Context) error {\n\treturn modes.GetDaemonLoader().Load(ctx)\n}\n"
  },
  {
    "path": "packages/chain/notandroid.go",
    "content": "//go:build !android && !ios\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage chain\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc httpListener(ListenHTTPHost string, route http.Handler) {\n\tl, err := net.Listen(\"tcp\", ListenHTTPHost)\n\tlog.WithFields(log.Fields{\"host\": ListenHTTPHost, \"type\": consts.NetworkError}).Debug(\"trying to listen at\")\n\tif err == nil {\n\t\tlog.WithFields(log.Fields{\"host\": ListenHTTPHost}).Info(\"listening at\")\n\t} else {\n\t\tlog.WithFields(log.Fields{\"host\": ListenHTTPHost, \"error\": err, \"type\": consts.NetworkError}).Debug(\"cannot listen at host\")\n\t}\n\n\tgo func() {\n\t\tsrv := &http.Server{Handler: route}\n\t\terr = srv.Serve(l)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"host\": ListenHTTPHost, \"error\": err, \"type\": consts.NetworkError}).Error(\"serving http at host\")\n\t\t\tpanic(err)\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "packages/chain/start.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage chain\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/jsonrpc\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/api\"\n\t\"github.com/IBAX-io/go-ibax/packages/chain/daemonsctl\"\n\t\"github.com/IBAX-io/go-ibax/packages/chain/system\"\n\n\tlogtools \"github.com/IBAX-io/go-ibax/packages/common/log\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/daemons\"\n\t\"github.com/IBAX-io/go-ibax/packages/modes\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/httpserver\"\n\t\"github.com/IBAX-io/go-ibax/packages/publisher\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/statsd\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc init() {\n\tjwtSecret := []byte(crypto.RandSeq(15))\n\tjsonrpc.InitJwtSecret(jwtSecret)\n\tapi.InitJwtSecret(jwtSecret)\n}\n\n// Start starts the main code of the program\nfunc Start() {\n\tvar err error\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlog.WithFields(log.Fields{\"panic\": r, \"type\": consts.PanicRecoveredError}).Error(\"recovered panic\")\n\t\t\tpanic(r)\n\t\t}\n\t}()\n\texitErr := func(code int) {\n\t\tsystem.RemovePidFile()\n\t\tsqldb.GormClose()\n\t\tstatsd.Close()\n\t\tos.Exit(code)\n\t}\n\tf := utils.LockOrDie(conf.Config.DirPathConf.LockFilePath)\n\tdefer f.Unlock()\n\tif err := utils.MakeDirectory(conf.Config.DirPathConf.TempDir); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"dir\": conf.Config.DirPathConf.TempDir}).Error(\"can't create temporary directory\")\n\t\texitErr(1)\n\t}\n\n\t// save the current pid and version\n\tif err := system.CreatePidFile(); err != nil {\n\t\tlog.Errorf(\"can't create pid: %s\", err)\n\t\texitErr(1)\n\t}\n\tdefer system.RemovePidFile()\n\n\tlog.WithFields(log.Fields{\"work_dir\": conf.Config.DirPathConf.DataDir, \"version\": consts.Version()}).Info(\"started with\")\n\n\tif err = initLogs(); err != nil {\n\t\tlog.Errorf(\"logs init failed: %v\\n\", utils.ErrInfo(err))\n\t\texitErr(1)\n\t}\n\n\tif conf.Config.FuncBench {\n\t\tlog.Warning(\"Warning! Access checking is disabled in some built-in functions\")\n\t}\n\n\tpublisher.InitCentrifugo(conf.Config.Centrifugo)\n\tinitStatsd()\n\n\trand.Seed(time.Now().UTC().UnixNano())\n\tsmart.InitVM()\n\tif err := syspar.ReadNodeKeys(); err != nil {\n\t\tlog.Errorf(\"can't read node keys: %s\", err)\n\t\texitErr(1)\n\t}\n\n\tif err = sqldb.GormInit(conf.Config.DB); err != nil {\n\t\tlog.WithFields(log.Fields{\n\t\t\t\"db_user\": conf.Config.DB.User, \"db_password\": conf.Config.DB.Password, \"db_name\": conf.Config.DB.Name, \"type\": consts.DBError,\n\t\t}).Error(\"can't init gorm\")\n\t\texitErr(1)\n\t}\n\n\tif sqldb.DBConn != nil {\n\t\tif err := sqldb.UpdateSchema(); err != nil {\n\t\t\tlog.WithError(err).Error(\"on running update migrations\")\n\t\t\texitErr(1)\n\t\t}\n\t\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\t\tif err == nil && len(candidateNodes) > 0 {\n\t\t\tsyspar.SetRunModel(consts.CandidateNodeMode)\n\t\t} else {\n\t\t\tsyspar.SetRunModel(consts.HonorNodeMode)\n\t\t}\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tutils.CancelFunc = cancel\n\t\tutils.ReturnCh = make(chan string)\n\n\t\t// The installation process is already finished (where user has specified DB and where wallet has been restarted)\n\t\terr = daemonsctl.RunAllDaemons(ctx)\n\t\tlog.Info(\"Daemons started\")\n\t\tif err != nil {\n\t\t\texitErr(1)\n\t\t}\n\t}\n\n\tdaemons.WaitForSignals()\n\n\tinitRoutes(conf.Config.HTTP.Str())\n\n\tselect {}\n}\n\nfunc initStatsd() {\n\tif err := statsd.Init(conf.Config.StatsD); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.StatsdError, \"error\": err}).Fatal(\"cannot initialize statsd\")\n\t}\n}\n\nfunc initLogs() error {\n\tswitch conf.Config.Log.LogFormat {\n\tcase \"json\":\n\t\tlog.SetFormatter(&log.JSONFormatter{})\n\tdefault:\n\t\tlog.SetFormatter(&log.TextFormatter{})\n\t}\n\tswitch conf.Config.Log.LogTo {\n\tcase \"stdout\":\n\t\tlog.SetOutput(os.Stdout)\n\tcase \"syslog\":\n\t\tfacility := conf.Config.Log.Syslog.Facility\n\t\ttag := conf.Config.Log.Syslog.Tag\n\t\tsysLogHook, err := logtools.NewSyslogHook(facility, tag)\n\t\tif err != nil {\n\t\t\tlog.WithError(err).Error(\"Unable to connect to local syslog daemon\")\n\t\t} else {\n\t\t\tlog.AddHook(sysLogHook)\n\t\t}\n\tdefault:\n\t\tfileName := filepath.Join(conf.Config.DirPathConf.DataDir, conf.Config.Log.LogTo)\n\t\topenMode := os.O_APPEND\n\t\tif _, err := os.Stat(fileName); os.IsNotExist(err) {\n\t\t\topenMode = os.O_CREATE\n\t\t}\n\n\t\tf, err := os.OpenFile(fileName, os.O_WRONLY|openMode, 0755)\n\t\tif err != nil {\n\t\t\tfmt.Fprintln(os.Stderr, \"Can't open log file: \", fileName)\n\t\t\treturn err\n\t\t}\n\t\tlog.SetOutput(f)\n\t}\n\n\tswitch conf.Config.Log.LogLevel {\n\tcase \"DEBUG\":\n\t\tlog.SetLevel(log.DebugLevel)\n\tcase \"INFO\":\n\t\tlog.SetLevel(log.InfoLevel)\n\tcase \"WARN\":\n\t\tlog.SetLevel(log.WarnLevel)\n\tcase \"ERROR\":\n\t\tlog.SetLevel(log.ErrorLevel)\n\tdefault:\n\t\tlog.SetLevel(log.InfoLevel)\n\t}\n\n\tlog.AddHook(logtools.ContextHook{})\n\tlog.AddHook(logtools.HexHook{})\n\n\treturn nil\n}\n\nfunc initRoutes(listenHost string) {\n\thandler := modes.RegisterRoutes()\n\thandler = httpserver.NewMaxBodyReader(handler, conf.Config.LocalConf.HTTPServerMaxBodySize)\n\tif conf.Config.JsonRPC.Enabled {\n\t\thandler = modes.RegisterJsonRPCRoutes(handler)\n\t}\n\thandler = api.WithCors(handler)\n\n\tif conf.Config.TLSConf.Enabled {\n\t\tif len(conf.Config.TLSConf.TLSCert) == 0 || len(conf.Config.TLSConf.TLSKey) == 0 {\n\t\t\tlog.Fatal(\"-tls-cert/TLSCert and -tls-key/TLSKey must be specified with -tls/TLS\")\n\t\t}\n\t\tif _, err := os.Stat(conf.Config.TLSConf.TLSCert); os.IsNotExist(err) {\n\t\t\tlog.WithError(err).Fatalf(`Filepath -tls-cert/TLSCert = %s is invalid`, conf.Config.TLSConf.TLSCert)\n\t\t}\n\t\tif _, err := os.Stat(conf.Config.TLSConf.TLSKey); os.IsNotExist(err) {\n\t\t\tlog.WithError(err).Fatalf(`Filepath -tls-key/TLSKey = %s is invalid`, conf.Config.TLSConf.TLSKey)\n\t\t}\n\t\tgo func() {\n\t\t\ts := &http.Server{\n\t\t\t\tAddr:    listenHost,\n\t\t\t\tHandler: handler,\n\t\t\t\tTLSConfig: &tls.Config{\n\t\t\t\t\tMinVersion:             tls.VersionTLS12,\n\t\t\t\t\tSessionTicketsDisabled: true,\n\t\t\t\t\t//ClientAuth:   tls.RequireAndVerifyClientCert,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := s.ListenAndServeTLS(conf.Config.TLSConf.TLSCert, conf.Config.TLSConf.TLSKey)\n\n\t\t\t//err := http.ListenAndServeTLS(listenHost, conf.Config.TLSCert, conf.Config.TLSKey, handler)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"host\": listenHost, \"error\": err, \"type\": consts.NetworkError}).Fatal(\"Listening TLS server\")\n\t\t\t}\n\t\t}()\n\t\tlog.WithFields(log.Fields{\"host\": listenHost}).Info(\"listening with TLS at\")\n\t\treturn\n\t}\n\n\thttpListener(listenHost, handler)\n}\n"
  },
  {
    "path": "packages/chain/system/pid.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage system\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// CreatePidFile creats pid file\nfunc CreatePidFile() error {\n\tkillOldPid()\n\tpid := os.Getpid()\n\tpidAndVer, err := json.Marshal(map[string]string{\n\t\t\"pid\":     converter.IntToStr(pid),\n\t\t\"version\": consts.Version(),\n\t})\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"pid\": pid, \"error\": err, \"type\": consts.JSONMarshallError}).Error(\"marshalling pid to json\")\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(conf.Config.GetPidPath(), pidAndVer, 0644)\n}\n\n// RemovePidFile removes pid file\nfunc RemovePidFile() error {\n\treturn os.Remove(conf.Config.GetPidPath())\n}\n\n// ReadPidFile reads pid file\nfunc ReadPidFile() (int, error) {\n\tpidPath := conf.Config.GetPidPath()\n\tif _, err := os.Stat(pidPath); err != nil {\n\t\treturn 0, nil\n\t}\n\n\tdata, err := os.ReadFile(pidPath)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"path\": pidPath, \"error\": err, \"type\": consts.IOError}).Error(\"reading pid file\")\n\t\treturn 0, err\n\t}\n\n\tpid, err := strconv.Atoi(strings.TrimSpace(string(data)))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"data\": data, \"error\": err, \"type\": consts.ConversionError}).Error(\"pid file data to int\")\n\t}\n\treturn pid, err\n}\n\nfunc killOldPid() {\n\tpidPath := conf.Config.GetPidPath()\n\tif _, err := os.Stat(pidPath); err == nil {\n\t\tdat, err := os.ReadFile(pidPath)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"path\": pidPath, \"error\": err, \"type\": consts.IOError}).Error(\"reading pid file\")\n\t\t}\n\t\tvar pidMap map[string]string\n\t\terr = json.Unmarshal(dat, &pidMap)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"data\": dat, \"error\": err, \"type\": consts.JSONUnmarshallError}).Error(\"unmarshalling pid map\")\n\t\t}\n\t\tlog.WithFields(log.Fields{\"path\": conf.Config.DirPathConf.DataDir + pidMap[\"pid\"]}).Debug(\"old pid path\")\n\n\t\tKillPid(pidMap[\"pid\"])\n\t\tif fmt.Sprintf(\"%s\", err) != \"null\" {\n\t\t\t// give 15 sec to end the previous process\n\t\t\tfor i := 0; i < 5; i++ {\n\t\t\t\tif _, err := os.Stat(conf.Config.GetPidPath()); err == nil {\n\t\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/chain/system/unix.go",
    "content": "//go:build (linux || freebsd || darwin) && (386 || amd64 || arm64)\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage system\n\nimport (\n\t\"syscall\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// KillPid is killing process by PID\nfunc KillPid(pid string) error {\n\terr := syscall.Kill(converter.StrToInt(pid), syscall.SIGTERM)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"pid\": pid, \"signal\": syscall.SIGTERM}).Error(\"Error killing process with pid\")\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/chain/system/windows.go",
    "content": "//go:build windows\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage system\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// KillPid kills the process with the specified pid\nfunc KillPid(pid string) error {\n\tif sqldb.DBConn != nil {\n\t\tsd := &sqldb.StopDaemon{StopTime: time.Now().Unix()}\n\t\terr := sd.Create()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Error creating StopDaemon\")\n\t\t\treturn err\n\t\t}\n\t}\n\trez, err := exec.Command(\"tasklist\", \"/fi\", \"PID eq \"+pid).Output()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CommandExecutionError, \"err\": err, \"cmd\": \"tasklist /fi PID eq\" + pid}).Error(\"Error executing command\")\n\t\treturn err\n\t}\n\tif string(rez) == \"\" {\n\t\treturn fmt.Errorf(\"null\")\n\t}\n\tlog.WithFields(log.Fields{\"cmd\": \"tasklist /fi PID eq \" + pid}).Debug(\"command execution result\")\n\tif ok, _ := regexp.MatchString(`(?i)PID`, string(rez)); !ok {\n\t\treturn fmt.Errorf(\"null\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/clbmanager/config.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage clbmanager\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"path/filepath\"\n)\n\nconst (\n\tinidDBCommand  = \"initDatabase\"\n\tgenKeysCommand = \"generateKeys\"\n\tstartCommand   = \"start\"\n)\n\n// ChildCLBConfig struct to manage child entry\ntype ChildCLBConfig struct {\n\tExecutable     string\n\tName           string\n\tDirectory      string\n\tDBUser         string\n\tDBPassword     string\n\tConfigFileName string\n\tLogTo          string\n\tLogLevel       string\n\tHTTPPort       int\n}\n\nfunc (c ChildCLBConfig) configCommand() *exec.Cmd {\n\n\targs := []string{\n\t\t\"config\",\n\t\tfmt.Sprintf(\"--path=%s\", c.configPath()),\n\t\tfmt.Sprintf(\"--dbUser=%s\", c.DBUser),\n\t\tfmt.Sprintf(\"--dbPassword=%s\", c.DBPassword),\n\t\tfmt.Sprintf(\"--dbName=%s\", c.Name),\n\t\tfmt.Sprintf(\"--httpPort=%d\", c.HTTPPort),\n\t\tfmt.Sprintf(\"--dataDir=%s\", c.Directory),\n\t\tfmt.Sprintf(\"--keysDir=%s\", c.Directory),\n\t\tfmt.Sprintf(\"--logTo=%s\", c.LogTo),\n\t\tfmt.Sprintf(\"--logLevel=%s\", c.LogLevel),\n\t\t\"--clbMode=CLB\",\n\t}\n\n\treturn exec.Command(c.Executable, args...)\n}\n\nfunc (c ChildCLBConfig) initDBCommand() *exec.Cmd {\n\treturn c.getCommand(inidDBCommand)\n}\n\nfunc (c ChildCLBConfig) generateKeysCommand() *exec.Cmd {\n\treturn c.getCommand(genKeysCommand)\n}\n\nfunc (c ChildCLBConfig) startCommand() *exec.Cmd {\n\treturn c.getCommand(startCommand)\n}\n\nfunc (c ChildCLBConfig) configPath() string {\n\treturn filepath.Join(c.Directory, c.ConfigFileName)\n}\n\nfunc (c ChildCLBConfig) getCommand(commandName string) *exec.Cmd {\n\targs := []string{\n\t\tcommandName,\n\t\tfmt.Sprintf(\"--config=%s\", c.configPath()),\n\t}\n\n\treturn exec.Command(c.Executable, args...)\n}\n"
  },
  {
    "path": "packages/clbmanager/manager.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage clbmanager\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/ochinchina/go-ini\"\n\tpConf \"github.com/ochinchina/supervisord/config\"\n\t\"github.com/ochinchina/supervisord/process\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tchildFolder        = \"configs\"\n\tcreateRoleTemplate = `CREATE ROLE %s WITH ENCRYPTED PASSWORD '%s' NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN`\n\tcreateDBTemplate   = `CREATE DATABASE %s OWNER %s`\n\n\tdropDBTemplate     = `DROP DATABASE IF EXISTS %s`\n\tdropOwnedTemplate  = `DROP OWNED BY %s CASCADE`\n\tdropDBRoleTemplate = `DROP ROLE IF EXISTS %s`\n\tcommandTemplate    = `%s start --config=%s`\n\n\talreadyExistsErrorTemplate = `clb '%s' already exists`\n)\n\nvar (\n\terrWrongMode        = errors.New(\"node must be running as CLBMaster\")\n\terrIncorrectCLBName = errors.New(\"the name cannot begit with a number and must contain alphabetical symbols and numbers\")\n)\n\n// CLBManager struct\ntype CLBManager struct {\n\tprocesses        *process.Manager\n\texecPath         string\n\tchildConfigsPath string\n}\n\nvar (\n\tManager *CLBManager\n)\n\nfunc prepareWorkDir() (string, error) {\n\tchildConfigsPath := path.Join(conf.Config.DirPathConf.DataDir, childFolder)\n\n\tif _, err := os.Stat(childConfigsPath); os.IsNotExist(err) {\n\t\tif err := os.Mkdir(childConfigsPath, 0700); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"creating configs directory\")\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\treturn childConfigsPath, nil\n}\n\n// CreateCLB creates one instance of CLB\nfunc (mgr *CLBManager) CreateCLB(name, dbUser, dbPassword string, port int) error {\n\tif err := checkCLBName(name); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Error(\"on check CLB name\")\n\t\treturn errIncorrectCLBName\n\t}\n\n\tvar err error\n\tvar cancelChain []func()\n\n\tdefer func() {\n\t\tif err == nil {\n\t\t\treturn\n\t\t}\n\n\t\tfor _, cancelFunc := range cancelChain {\n\t\t\tcancelFunc()\n\t\t}\n\t}()\n\n\tconfig := ChildCLBConfig{\n\t\tExecutable:     mgr.execPath,\n\t\tName:           name,\n\t\tDirectory:      path.Join(mgr.childConfigsPath, name),\n\t\tDBUser:         dbUser,\n\t\tDBPassword:     dbPassword,\n\t\tConfigFileName: consts.DefaultConfigFile,\n\t\tHTTPPort:       port,\n\t\tLogTo:          fmt.Sprintf(\"%s_%s\", name, conf.Config.Log.LogTo),\n\t\tLogLevel:       conf.Config.Log.LogLevel,\n\t}\n\n\tif mgr.processes == nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.WrongModeError, \"error\": errWrongMode}).Error(\"creating new CLB\")\n\t\treturn errWrongMode\n\t}\n\n\tif err = mgr.createCLBDB(name, dbUser, dbPassword); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on creating CLB DB\")\n\t\treturn fmt.Errorf(alreadyExistsErrorTemplate, name)\n\t}\n\n\tcancelChain = append(cancelChain, func() {\n\t\tdropDb(name, dbUser)\n\t})\n\n\tdirPath := path.Join(mgr.childConfigsPath, name)\n\tif directoryExists(dirPath) {\n\t\terr = fmt.Errorf(alreadyExistsErrorTemplate, name)\n\t\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err, \"dirPath\": dirPath}).Error(\"on check directory\")\n\t\treturn err\n\t}\n\n\tif err = mgr.initCLBDir(name); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"DirName\": name, \"error\": err}).Error(\"on init CLB dir\")\n\t\treturn err\n\t}\n\n\tcancelChain = append(cancelChain, func() {\n\t\tdropCLBDir(mgr.childConfigsPath, name)\n\t})\n\n\tcmd := config.configCommand()\n\tif err = cmd.Run(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"args\": cmd.Args, \"error\": err}).Error(\"on run config command\")\n\t\treturn err\n\t}\n\n\tif err = config.generateKeysCommand().Run(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"args\": cmd.Args, \"error\": err}).Error(\"on run generateKeys command\")\n\t\treturn err\n\t}\n\n\tif err = config.initDBCommand().Run(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"args\": cmd.Args}).Error(\"on run initDB command\")\n\t\treturn err\n\t}\n\n\tprocConfEntry := pConf.NewEntry(config.Directory)\n\tprocConfEntry.Name = \"program:\" + name\n\tcommand := fmt.Sprintf(\"%s start --config=%s\", config.Executable, filepath.Join(config.Directory, consts.DefaultConfigFile))\n\tlog.Infoln(command)\n\tsection := ini.NewSection(procConfEntry.Name)\n\tsection.Add(\"command\", command)\n\tproc := process.NewProcess(\"clbMaster\", procConfEntry)\n\n\tmgr.processes.Add(name, proc)\n\tmgr.processes.Find(name).Start(true)\n\treturn nil\n}\n\n// ListProcess returns list of process names with state of process\nfunc (mgr *CLBManager) ListProcess() (map[string]string, error) {\n\tif mgr.processes == nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.WrongModeError, \"error\": errWrongMode}).Error(\"get CLB list\")\n\t\treturn nil, errWrongMode\n\t}\n\n\tlist := make(map[string]string)\n\n\tmgr.processes.ForEachProcess(func(p *process.Process) {\n\t\tlist[p.GetName()] = p.GetState().String()\n\t})\n\n\treturn list, nil\n}\n\nfunc (mgr *CLBManager) ListProcessWithPorts() (map[string]string, error) {\n\tlist, err := mgr.ListProcess()\n\tif err != nil {\n\t\treturn list, err\n\t}\n\n\tfor name, status := range list {\n\t\tpath := path.Join(mgr.childConfigsPath, name, consts.DefaultConfigFile)\n\t\tc := &conf.GlobalConfig{}\n\t\tif err := conf.LoadConfigToVar(path, c); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": \"dbError\", \"error\": err, \"path\": path}).Warn(\"on loading child CLB config\")\n\t\t\tcontinue\n\t\t}\n\n\t\tlist[name] = fmt.Sprintf(\"%s %d\", status, c.HTTP.Port)\n\t}\n\n\treturn list, err\n}\n\n// DeleteCLB stop CLB process and remove CLB folder\nfunc (mgr *CLBManager) DeleteCLB(name string) error {\n\n\tif mgr.processes == nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.WrongModeError, \"error\": errWrongMode}).Error(\"deleting CLB\")\n\t\treturn errWrongMode\n\t}\n\n\tmgr.StopCLB(name)\n\tmgr.processes.Remove(name)\n\tclbDir := path.Join(mgr.childConfigsPath, name)\n\tclbConfigPath := filepath.Join(clbDir, consts.DefaultConfigFile)\n\tclbConfig, err := conf.GetConfigFromPath(clbConfigPath)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Errorf(\"Getting config from path %s\", clbConfigPath)\n\t\treturn fmt.Errorf(`CLB '%s' is not exists`, name)\n\t}\n\n\ttime.Sleep(1 * time.Second)\n\tif err := dropDb(clbConfig.DB.Name, clbConfig.DB.User); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.RemoveAll(clbDir)\n}\n\n// StartCLB find process and then start him\nfunc (mgr *CLBManager) StartCLB(name string) error {\n\n\tif mgr.processes == nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.WrongModeError, \"error\": errWrongMode}).Error(\"starting CLB\")\n\t\treturn errWrongMode\n\t}\n\n\tproc := mgr.processes.Find(name)\n\tif proc == nil {\n\t\terr := fmt.Errorf(`CLB '%s' is not exists`, name)\n\t\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Error(\"on find CLB process\")\n\t\treturn err\n\t}\n\n\tstate := proc.GetState()\n\tif state == process.Stopped ||\n\t\tstate == process.Exited ||\n\t\tstate == process.Fatal {\n\t\tproc.Start(true)\n\t\tlog.WithFields(log.Fields{\"clb_name\": name}).Info(\"CLB started\")\n\t\treturn nil\n\t}\n\n\terr := fmt.Errorf(\"CLB '%s' is %s\", name, state)\n\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Error(\"on starting CLB\")\n\treturn err\n}\n\n// StopCLB find process with definded name and then stop him\nfunc (mgr *CLBManager) StopCLB(name string) error {\n\n\tif mgr.processes == nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.WrongModeError, \"error\": errWrongMode}).Error(\"on stopping CLB process\")\n\t\treturn errWrongMode\n\t}\n\n\tproc := mgr.processes.Find(name)\n\tif proc == nil {\n\t\terr := fmt.Errorf(`CLB '%s' is not exists`, name)\n\t\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Error(\"on find CLB process\")\n\t\treturn err\n\t}\n\n\tstate := proc.GetState()\n\tif state == process.Running ||\n\t\tstate == process.Starting {\n\t\tproc.Stop(true)\n\t\tlog.WithFields(log.Fields{\"clb_name\": name}).Info(\"CLB is stoped\")\n\t\treturn nil\n\t}\n\n\terr := fmt.Errorf(\"CLB '%s' is %s\", name, state)\n\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Error(\"on stoping CLB\")\n\treturn err\n}\n\nfunc (mgr *CLBManager) createCLBDB(clbName, login, pass string) error {\n\n\tif err := sqldb.DBConn.Exec(fmt.Sprintf(createRoleTemplate, login, pass)).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating CLB DB User\")\n\t\treturn err\n\t}\n\n\tif err := sqldb.DBConn.Exec(fmt.Sprintf(createDBTemplate, clbName, login)).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating CLB DB\")\n\n\t\tif err := sqldb.GetDB(nil).Exec(fmt.Sprintf(dropDBRoleTemplate, login)).Error; err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"role\": login}).Error(\"on deleting clb role\")\n\t\t\treturn err\n\t\t}\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (mgr *CLBManager) initCLBDir(clbName string) error {\n\n\tclbDirName := path.Join(mgr.childConfigsPath, clbName)\n\tif _, err := os.Stat(clbDirName); os.IsNotExist(err) {\n\t\tif err := os.Mkdir(clbDirName, 0700); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"creating CLB directory\")\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc InitCLBManager() {\n\tif !conf.Config.IsCLBMaster() {\n\t\treturn\n\t}\n\n\texecPath, err := os.Executable()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Fatal(\"on determine executable path\")\n\t}\n\n\tchildConfigsPath, err := prepareWorkDir()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CLBManagerError, \"error\": err}).Fatal(\"on prepare child configs folder\")\n\t}\n\n\tManager = &CLBManager{\n\t\tprocesses:        process.NewManager(),\n\t\texecPath:         execPath,\n\t\tchildConfigsPath: childConfigsPath,\n\t}\n\n\tlist, err := os.ReadDir(childConfigsPath)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"path\": childConfigsPath}).Fatal(\"on read child CLB directory\")\n\t}\n\n\tfor _, item := range list {\n\t\tif item.IsDir() {\n\t\t\tprocDir := path.Join(Manager.childConfigsPath, item.Name())\n\t\t\tcommandStr := fmt.Sprintf(commandTemplate, Manager.execPath, filepath.Join(procDir, consts.DefaultConfigFile))\n\t\t\tlog.Info(commandStr)\n\t\t\tconfEntry := pConf.NewEntry(procDir)\n\t\t\tconfEntry.Name = \"program:\" + item.Name()\n\t\t\tsection := ini.NewSection(confEntry.Name)\n\t\t\tsection.Add(\"command\", commandStr)\n\t\t\tsection.Add(\"redirect_stderr\", \"true\")\n\t\t\tsection.Add(\"autostart\", \"true\")\n\t\t\tsection.Add(\"autorestart\", \"true\")\n\n\t\t\tproc := process.NewProcess(\"clbMaster\", confEntry)\n\t\t\tManager.processes.Add(item.Name(), proc)\n\t\t\tproc.Start(true)\n\t\t}\n\t}\n}\n\nfunc dropDb(name, role string) error {\n\tif err := sqldb.NewDbTransaction(nil).DropDatabase(name); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"db_name\": name}).Error(\"Deleting clb db\")\n\t\treturn err\n\t}\n\n\tif err := sqldb.GetDB(nil).Exec(fmt.Sprintf(dropDBRoleTemplate, role)).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"role\": role}).Error(\"on deleting clb role\")\n\t}\n\treturn nil\n}\n\nfunc dropCLBDir(configsPath, clbName string) error {\n\tpath := path.Join(configsPath, clbName)\n\tif directoryExists(path) {\n\t\tos.RemoveAll(path)\n\t}\n\n\tlog.WithFields(log.Fields{\"path\": path}).Error(\"droping dir is not exists\")\n\treturn nil\n}\n\nfunc directoryExists(path string) bool {\n\tif _, err := os.Stat(path); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc checkCLBName(name string) error {\n\n\tname = strings.ToLower(name)\n\n\tfor i, c := range name {\n\t\tif unicode.IsDigit(c) && i == 0 {\n\t\t\treturn errors.New(\"the name cannot begin with a number\")\n\t\t}\n\t\tif !unicode.IsDigit(c) && !unicode.Is(unicode.Latin, c) {\n\t\t\treturn errors.New(\"Incorrect symbol\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (mgr *CLBManager) configByName(name string) (*conf.GlobalConfig, error) {\n\tpath := path.Join(mgr.childConfigsPath)\n\tc := &conf.GlobalConfig{}\n\terr := conf.LoadConfigToVar(path, c)\n\treturn c, err\n}\n"
  },
  {
    "path": "packages/common/crypto/asymalgo/asymalgo.go",
    "content": "package asymalgo\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math/big\"\n)\n\n// ParseSign converts the hex signature to r and s big number\nfunc ParseSign(sign string) (*big.Int, *big.Int, error) {\n\tvar (\n\t\tbinSign []byte\n\t\terr     error\n\t)\n\t//\tvar off int\n\tparse := func(bsign []byte) []byte {\n\t\tblen := int(bsign[1])\n\t\tif blen > len(bsign)-2 {\n\t\t\treturn nil\n\t\t}\n\t\tret := bsign[2 : 2+blen]\n\t\tif len(ret) > 32 {\n\t\t\tret = ret[len(ret)-32:]\n\t\t} else if len(ret) < 32 {\n\t\t\tret = append(bytes.Repeat([]byte{0}, 32-len(ret)), ret...)\n\t\t}\n\t\treturn ret\n\t}\n\tif len(sign) > 128 {\n\t\tbinSign, err = hex.DecodeString(sign)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"decoding sign from string: %w\", err)\n\t\t}\n\t\tleft := parse(binSign[2:])\n\t\tif left == nil || int(binSign[3])+6 > len(binSign) {\n\t\t\treturn nil, nil, fmt.Errorf(`wrong left parsing`)\n\t\t}\n\t\tright := parse(binSign[4+binSign[3]:])\n\t\tif right == nil {\n\t\t\treturn nil, nil, fmt.Errorf(`wrong right parsing`)\n\t\t}\n\t\tsign = hex.EncodeToString(append(left, right...))\n\t} else if len(sign) < 128 {\n\t\treturn nil, nil, fmt.Errorf(`wrong len of signature %d`, len(sign))\n\t}\n\tall, err := hex.DecodeString(sign[:])\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"wrong signature size: %w\", err)\n\t}\n\treturn new(big.Int).SetBytes(all[:32]), new(big.Int).SetBytes(all[len(all)-32:]), nil\n}\n\n// FillLeft is filling slice\nfunc FillLeft(slice []byte) []byte {\n\tif len(slice) >= 32 {\n\t\treturn slice\n\t}\n\treturn append(make([]byte, 32-len(slice)), slice...)\n}\n"
  },
  {
    "path": "packages/common/crypto/asymalgo/error.go",
    "content": "package asymalgo\n\nimport \"errors\"\n\nvar (\n\t// ErrSigningEmpty is Signing empty value error\n\tErrSigningEmpty = errors.New(\"Signing empty value\")\n\t// ErrCheckingSignEmpty is Checking sign of empty error\n\tErrCheckingSignEmpty = errors.New(\"Cheking sign of empty\")\n\t// ErrIncorrectSign is Incorrect sign\n\tErrIncorrectSign = errors.New(\"Incorrect sign\")\n)\n"
  },
  {
    "path": "packages/common/crypto/asymalgo/p256.go",
    "content": "package asymalgo\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\tcrand \"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n)\n\ntype P256 struct{}\n\nfunc (e *P256) GenKeyPair() ([]byte, []byte, error) {\n\tvar curve elliptic.Curve\n\tcurve = elliptic.P256()\n\tprivate, err := ecdsa.GenerateKey(curve, crand.Reader)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn private.D.Bytes(), append(FillLeft(private.PublicKey.X.Bytes()), FillLeft(private.PublicKey.Y.Bytes())...), nil\n}\n\nfunc (e *P256) Sign(privateKey, hash []byte) ([]byte, error) {\n\tif len(hash) == 0 {\n\t\treturn nil, ErrSigningEmpty\n\t}\n\tpriv := new(ecdsa.PrivateKey)\n\tpriv.PublicKey.Curve = elliptic.P256()\n\tpriv.D = new(big.Int).SetBytes(privateKey)\n\tr, s, err := ecdsa.Sign(crand.Reader, priv, hash)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn append(FillLeft(r.Bytes()), FillLeft(s.Bytes())...), nil\n}\n\nfunc (e *P256) Verify(public, hash, signature []byte) (bool, error) {\n\tif len(public) == 0 {\n\t\treturn false, ErrCheckingSignEmpty\n\t}\n\tif len(hash) == 0 {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(data) == 0\")\n\t}\n\tif len(public) != consts.PubkeySizeLength {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(public) = %d\", len(public))\n\t}\n\tif len(signature) == 0 {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(signature) == 0\")\n\t}\n\n\tpubkey := new(ecdsa.PublicKey)\n\tpubkey.Curve = elliptic.P256()\n\tpubkey.X = new(big.Int).SetBytes(public[0:consts.PrivkeyLength])\n\tpubkey.Y = new(big.Int).SetBytes(public[consts.PrivkeyLength:])\n\tr, s, err := ParseSign(hex.EncodeToString(signature))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tverify := ecdsa.Verify(pubkey, hash, r, s)\n\tif !verify {\n\t\treturn false, ErrIncorrectSign\n\t}\n\treturn true, nil\n}\n\nfunc (e *P256) PrivateToPublic(key []byte) ([]byte, error) {\n\tpubkeyCurve := elliptic.P256()\n\tpriv := new(ecdsa.PrivateKey)\n\tpriv.PublicKey.Curve = pubkeyCurve\n\tpriv.D = new(big.Int).SetBytes(key)\n\tpriv.PublicKey.X, priv.PublicKey.Y = pubkeyCurve.ScalarBaseMult(key)\n\treturn append(FillLeft(priv.PublicKey.X.Bytes()), FillLeft(priv.PublicKey.Y.Bytes())...), nil\n}\n"
  },
  {
    "path": "packages/common/crypto/asymalgo/secp256k1.go",
    "content": "package asymalgo\n\nimport (\n\t\"crypto/ecdsa\"\n\n\tcrand \"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\tsecp \"github.com/decred/dcrd/dcrec/secp256k1/v4\"\n)\n\ntype Secp256k1 struct{}\n\nfunc (s *Secp256k1) GenKeyPair() ([]byte, []byte, error) {\n\tpriv, err := ecdsa.GenerateKey(secp.S256(), crand.Reader)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tpub := append(FillLeft(priv.X.Bytes()), FillLeft(priv.Y.Bytes())...)\n\treturn priv.D.Bytes(), pub, nil\n}\n\nfunc (s *Secp256k1) Sign(privateKey, hash []byte) ([]byte, error) {\n\tif len(hash) == 0 {\n\t\treturn nil, ErrSigningEmpty\n\t}\n\tpubkeyCurve := secp.S256()\n\tbi := new(big.Int).SetBytes(privateKey)\n\tpriv := new(ecdsa.PrivateKey)\n\tpriv.PublicKey.Curve = pubkeyCurve\n\tpriv.D = bi\n\tr, s_, err := ecdsa.Sign(crand.Reader, priv, hash)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := append(FillLeft(r.Bytes()), FillLeft(s_.Bytes())...)\n\treturn ret, nil\n\n}\n\nfunc (s *Secp256k1) Verify(public, hash, signature []byte) (bool, error) {\n\tif len(public) == 0 {\n\t\treturn false, ErrCheckingSignEmpty\n\t}\n\tif len(hash) == 0 {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(data) == 0\")\n\t}\n\tif len(public) != consts.PubkeySizeLength {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(public) = %d\", len(public))\n\t}\n\tif len(signature) == 0 {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(signature) == 0\")\n\t}\n\tpubkeyCurve := secp.S256()\n\tpubkey := new(ecdsa.PublicKey)\n\tpubkey.Curve = pubkeyCurve\n\tpubkey.X = new(big.Int).SetBytes(public[0:consts.PrivkeyLength])\n\tpubkey.Y = new(big.Int).SetBytes(public[consts.PrivkeyLength:])\n\tr, s_, err := ParseSign(hex.EncodeToString(signature))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tverify := ecdsa.Verify(pubkey, hash, r, s_)\n\tif !verify {\n\t\treturn false, ErrIncorrectSign\n\t}\n\treturn true, nil\n}\n\nfunc (s *Secp256k1) PrivateToPublic(key []byte) ([]byte, error) {\n\tpriv := secp.PrivKeyFromBytes(key)\n\treturn priv.PubKey().SerializeUncompressed()[1:], nil\n}\n"
  },
  {
    "path": "packages/common/crypto/asymalgo/sm2.go",
    "content": "package asymalgo\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/tjfoc/gmsm/sm2\"\n)\n\ntype SM2 struct{}\n\nfunc (s *SM2) GenKeyPair() ([]byte, []byte, error) {\n\tpriv, err := sm2.GenerateKey(rand.Reader)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn priv.D.Bytes(), append(FillLeft(priv.PublicKey.X.Bytes()), FillLeft(priv.PublicKey.Y.Bytes())...), nil\n}\n\nfunc (s *SM2) Sign(privateKey, hash []byte) ([]byte, error) {\n\tpubkeyCurve := sm2.P256Sm2()\n\tbi := new(big.Int).SetBytes(privateKey)\n\tpriv := new(sm2.PrivateKey)\n\tpriv.PublicKey.Curve = pubkeyCurve\n\tpriv.D = bi\n\tpriv.PublicKey.X, priv.PublicKey.Y = pubkeyCurve.ScalarBaseMult(bi.Bytes())\n\treturn priv.Sign(rand.Reader, hash, nil)\n}\n\nfunc (s *SM2) Verify(public, hash, signature []byte) (bool, error) {\n\tif len(public) == 0 {\n\t\treturn false, ErrCheckingSignEmpty\n\t}\n\tif len(hash) == 0 {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(data) == 0\")\n\t}\n\tif len(public) != consts.PubkeySizeLength {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(public) = %d\", len(public))\n\t}\n\tif len(signature) == 0 {\n\t\treturn false, fmt.Errorf(\"invalid parameters len(signature) == 0\")\n\t}\n\tpubkey := new(sm2.PublicKey)\n\tpubkey.Curve = sm2.P256Sm2()\n\tpubkey.X = new(big.Int).SetBytes(public[0:consts.PrivkeyLength])\n\tpubkey.Y = new(big.Int).SetBytes(public[consts.PrivkeyLength:])\n\tverify := pubkey.Verify(hash, signature)\n\tif !verify {\n\t\treturn false, ErrIncorrectSign\n\t}\n\treturn true, nil\n}\n\nfunc (s *SM2) PrivateToPublic(key []byte) ([]byte, error) {\n\tpubkeyCurve := sm2.P256Sm2()\n\tbi := new(big.Int).SetBytes(key)\n\tpriv := new(sm2.PrivateKey)\n\tpriv.PublicKey.Curve = pubkeyCurve\n\tpriv.D = bi\n\tpriv.PublicKey.X, priv.PublicKey.Y = pubkeyCurve.ScalarBaseMult(key)\n\treturn append(FillLeft(priv.PublicKey.X.Bytes()), FillLeft(priv.PublicKey.Y.Bytes())...), nil\n}\n"
  },
  {
    "path": "packages/common/crypto/base58/base58.go",
    "content": "package base58\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"math/big\"\n)\n\nvar base58Alphabets = []byte(\"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\")\n\nfunc ToHexAddress(address string) string {\n\treturn hex.EncodeToString(base58Decode([]byte(address)))\n}\n\nfunc FromHexAddress(hexAddress string) (string, error) {\n\taddrByte, err := hex.DecodeString(hexAddress)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tsha := sha256.New()\n\tsha.Write(addrByte)\n\tshaStr := sha.Sum(nil)\n\n\tsha2 := sha256.New()\n\tsha2.Write(shaStr)\n\tshaStr2 := sha2.Sum(nil)\n\n\taddrByte = append(addrByte, shaStr2[:4]...)\n\treturn string(base58Encode(addrByte)), nil\n}\n\nfunc base58Encode(input []byte) []byte {\n\tx := big.NewInt(0).SetBytes(input)\n\tbase := big.NewInt(58)\n\tzero := big.NewInt(0)\n\tmod := &big.Int{}\n\tvar result []byte\n\tfor x.Cmp(zero) != 0 {\n\t\tx.DivMod(x, base, mod)\n\t\tresult = append(result, base58Alphabets[mod.Int64()])\n\t}\n\treverseBytes(result)\n\treturn result\n}\n\nfunc base58Decode(input []byte) []byte {\n\tresult := big.NewInt(0)\n\tfor _, b := range input {\n\t\tcharIndex := bytes.IndexByte(base58Alphabets, b)\n\t\tresult.Mul(result, big.NewInt(58))\n\t\tresult.Add(result, big.NewInt(int64(charIndex)))\n\t}\n\tdecoded := result.Bytes()\n\tif input[0] == base58Alphabets[0] {\n\t\tdecoded = append([]byte{0x00}, decoded...)\n\t}\n\treturn decoded[:len(decoded)-4]\n}\n\nfunc reverseBytes(data []byte) {\n\tfor i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {\n\t\tdata[i], data[j] = data[j], data[i]\n\t}\n}\n"
  },
  {
    "path": "packages/common/crypto/checksum.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage crypto\n\nimport \"hash/crc64\"\n\nvar (\n\ttable64 *crc64.Table\n)\n\nfunc init() {\n\ttable64 = crc64.MakeTable(crc64.ECMA)\n}\n\n// CalcChecksum is calculates checksum, returns crc64 sum.\nfunc CalcChecksum(input []byte) uint64 {\n\treturn crc64.Checksum(input, table64)\n}\n"
  },
  {
    "path": "packages/common/crypto/converter.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage crypto\n\nimport (\n\t\"crypto/sha512\"\n\t\"encoding/hex\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// CutPub removes the first 04 byte\nfunc CutPub(pubKey []byte) []byte {\n\tif len(pubKey) == 65 && pubKey[0] == 4 {\n\t\tpubKey = pubKey[1:]\n\t}\n\treturn pubKey\n}\n\n// Address gets int64 address from the public key\nfunc Address(pubKey []byte) int64 {\n\tpubKey = CutPub(pubKey)\n\th := Hash(pubKey)\n\th512 := sha512.Sum512(h[:])\n\tcrc := CalcChecksum(h512[:])\n\treturn buildChecksumConvert(crc)\n}\n\n// AddressSeed gets int64 address from the seed.\n// format: `IBAX Address By Seed:` + seed\nfunc AddressSeed(seed string) int64 {\n\th := Hash([]byte(\"IBAX Address By Seed:\" + seed))\n\th512 := sha512.Sum512(h[:])\n\tcrc := CalcChecksum(h512[:])\n\treturn buildChecksumConvert(crc)\n}\n\nfunc buildChecksumConvert(crc uint64) int64 {\n\tnum := strconv.FormatUint(crc, 10)\n\tval := RepeatPrefixed(num)\n\tv := val[:len(val)-1]\n\tsum := converter.CheckSum(v)\n\tuSum := uint64(sum)\n\treturn int64(crc - (crc % 10) + uSum)\n}\n\nfunc RepeatPrefixed(input string) []byte {\n\tconst size = consts.AddressLength\n\tif len(input) > size {\n\t\tinput = input[:size]\n\t}\n\treturn []byte(strings.Repeat(\"0\", size-len(input)) + input)\n}\n\n// KeyToAddress converts a public key to chain address XXXX-...-XXXX.\nfunc KeyToAddress(pubKey []byte) string {\n\treturn converter.AddressToString(Address(pubKey))\n}\n\n// GetWalletIDByPublicKey converts public key to wallet id\nfunc GetWalletIDByPublicKey(publicKey []byte) (int64, error) {\n\tkey, _ := HexToPub(string(publicKey))\n\treturn int64(Address(key)), nil\n}\n\n// HexToPub encodes hex string to []byte of pub key\nfunc HexToPub(pub string) ([]byte, error) {\n\tkey, err := hex.DecodeString(pub)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn CutPub(key), nil\n}\n\n// PubToHex decodes []byte of pub key to hex string\nfunc PubToHex(pub []byte) string {\n\tif len(pub) == 64 {\n\t\tpub = append([]byte{4}, pub...)\n\t}\n\treturn hex.EncodeToString(pub)\n}\n"
  },
  {
    "path": "packages/common/crypto/crypto.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage crypto\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/asymalgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/hashalgo\"\n)\n\nvar (\n\tasymAlgo AsymAlgo\n\thashAlgo HashAlgo\n)\n\nfunc NewAsymAlgo(a AsymAlgo) AsymProvider {\n\tswitch a {\n\tcase AsymAlgo_ECC_P256:\n\t\treturn &asymalgo.P256{}\n\tcase AsymAlgo_ECC_Secp256k1:\n\t\treturn &asymalgo.Secp256k1{}\n\tcase AsymAlgo_SM2:\n\t\treturn &asymalgo.SM2{}\n\t}\n\tpanic(fmt.Errorf(\"curve algo [%v] is not supported yet\", a))\n}\n\nfunc InitAsymAlgo(s string) {\n\tv, ok := AsymAlgo_value[s]\n\tif !ok {\n\t\tlog.Fatal(fmt.Errorf(\"curve algo [%v] is not supported yet, Run 'go-ibax config --help' for details\", s))\n\t}\n\tasymAlgo = AsymAlgo(v)\n\treturn\n}\n\nfunc GetAsymProvider() AsymProvider {\n\treturn NewAsymAlgo(asymAlgo)\n}\n\nfunc NewHashAlgo(a HashAlgo) HashProvider {\n\tswitch a {\n\tcase HashAlgo_SHA256:\n\t\treturn &hashalgo.SHA256{}\n\tcase HashAlgo_SM3:\n\t\treturn &hashalgo.SM3{}\n\tcase HashAlgo_KECCAK256:\n\t\treturn &hashalgo.Keccak256{}\n\tcase HashAlgo_SHA3_256:\n\t\treturn &hashalgo.Sha3256{}\n\t}\n\tpanic(fmt.Errorf(\"hash algo [%v] is not supported yet\", a))\n}\n\nfunc InitHashAlgo(s string) {\n\tv, ok := HashAlgo_value[s]\n\tif !ok {\n\t\tlog.Fatal(fmt.Errorf(\"hash algo [%v] is not supported yet, Run 'go-ibax config --help' for details\", s))\n\t}\n\thashAlgo = HashAlgo(v)\n\treturn\n}\n\nfunc GetHashProvider() HashProvider {\n\treturn NewHashAlgo(hashAlgo)\n}\n\n// GenKeyPair generates a random pair of private and public binary keys.\nfunc GenKeyPair() ([]byte, []byte, error) {\n\treturn GetAsymProvider().GenKeyPair()\n}\n\n// GenHexKeys generates a random pair of private and public hex keys.\nfunc GenHexKeys() (string, string, error) {\n\tpriv, pub, err := GenKeyPair()\n\tif err != nil {\n\t\treturn ``, ``, err\n\t}\n\treturn hex.EncodeToString(priv), PubToHex(pub), nil\n}\n\nfunc Sign(privateKey, data []byte) ([]byte, error) {\n\treturn GetAsymProvider().Sign(privateKey, Hash(data))\n}\n\nfunc Verify(public, data, signature []byte) (bool, error) {\n\treturn GetAsymProvider().Verify(public, Hash(data), signature)\n}\n\n// PrivateToPublic returns the public key for the specified private key.\nfunc PrivateToPublic(key []byte) ([]byte, error) {\n\treturn GetAsymProvider().PrivateToPublic(key)\n}\n\nfunc SignString(privateKeyHex, data string) ([]byte, error) {\n\tprivateKey, err := hex.DecodeString(privateKeyHex)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding private key from hex: %w\", err)\n\t}\n\treturn Sign(privateKey, []byte(data))\n}\n\nfunc GetHMAC(secret string, message string) ([]byte, error) {\n\treturn GetHashProvider().GetHMAC(secret, message)\n}\n\nfunc Hash(msg []byte) []byte {\n\treturn GetHashProvider().GetHash(msg)\n}\n\nfunc DoubleHash(msg []byte) []byte {\n\treturn GetHashProvider().DoubleHash(msg)\n}\n\nfunc HashHex(input []byte) string {\n\treturn hex.EncodeToString(Hash(input))\n}\n"
  },
  {
    "path": "packages/common/crypto/crypto.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: crypto.proto\n\npackage crypto\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/gogo/protobuf/proto\"\n\tmath \"math\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package\n\n// AsymAlgo is asymmetric algorithms\ntype AsymAlgo int32\n\nconst (\n\tAsymAlgo_ECC_P256      AsymAlgo = 0\n\tAsymAlgo_ECC_Secp256k1 AsymAlgo = 1\n\tAsymAlgo_SM2           AsymAlgo = 2\n\tAsymAlgo_ECC_P512      AsymAlgo = 3\n)\n\nvar AsymAlgo_name = map[int32]string{\n\t0: \"ECC_P256\",\n\t1: \"ECC_Secp256k1\",\n\t2: \"SM2\",\n\t3: \"ECC_P512\",\n}\n\nvar AsymAlgo_value = map[string]int32{\n\t\"ECC_P256\":      0,\n\t\"ECC_Secp256k1\": 1,\n\t\"SM2\":           2,\n\t\"ECC_P512\":      3,\n}\n\nfunc (x AsymAlgo) String() string {\n\treturn proto.EnumName(AsymAlgo_name, int32(x))\n}\n\nfunc (AsymAlgo) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_527278fb02d03321, []int{0}\n}\n\n// SymAlgo is symmetric algorithms\ntype SymAlgo int32\n\nconst (\n\tSymAlgo_AES SymAlgo = 0\n\tSymAlgo_SM4 SymAlgo = 1\n)\n\nvar SymAlgo_name = map[int32]string{\n\t0: \"AES\",\n\t1: \"SM4\",\n}\n\nvar SymAlgo_value = map[string]int32{\n\t\"AES\": 0,\n\t\"SM4\": 1,\n}\n\nfunc (x SymAlgo) String() string {\n\treturn proto.EnumName(SymAlgo_name, int32(x))\n}\n\nfunc (SymAlgo) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_527278fb02d03321, []int{1}\n}\n\n// HashAlgo is hash algorithms\ntype HashAlgo int32\n\nconst (\n\tHashAlgo_SHA256    HashAlgo = 0\n\tHashAlgo_KECCAK256 HashAlgo = 1\n\tHashAlgo_SM3       HashAlgo = 2\n\tHashAlgo_SHA3_256  HashAlgo = 3\n)\n\nvar HashAlgo_name = map[int32]string{\n\t0: \"SHA256\",\n\t1: \"KECCAK256\",\n\t2: \"SM3\",\n\t3: \"SHA3_256\",\n}\n\nvar HashAlgo_value = map[string]int32{\n\t\"SHA256\":    0,\n\t\"KECCAK256\": 1,\n\t\"SM3\":       2,\n\t\"SHA3_256\":  3,\n}\n\nfunc (x HashAlgo) String() string {\n\treturn proto.EnumName(HashAlgo_name, int32(x))\n}\n\nfunc (HashAlgo) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_527278fb02d03321, []int{2}\n}\n\nfunc init() {\n\tproto.RegisterEnum(\"crypto.AsymAlgo\", AsymAlgo_name, AsymAlgo_value)\n\tproto.RegisterEnum(\"crypto.SymAlgo\", SymAlgo_name, SymAlgo_value)\n\tproto.RegisterEnum(\"crypto.HashAlgo\", HashAlgo_name, HashAlgo_value)\n}\n\nfunc init() { proto.RegisterFile(\"crypto.proto\", fileDescriptor_527278fb02d03321) }\n\nvar fileDescriptor_527278fb02d03321 = []byte{\n\t// 243 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x2e, 0xaa, 0x2c,\n\t0x28, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0xb4, 0x9c, 0xb8, 0x38,\n\t0x1c, 0x8b, 0x2b, 0x73, 0x1d, 0x73, 0xd2, 0xf3, 0x85, 0x78, 0xb8, 0x38, 0x5c, 0x9d, 0x9d, 0xe3,\n\t0x03, 0x8c, 0x4c, 0xcd, 0x04, 0x18, 0x84, 0x04, 0xb9, 0x78, 0x41, 0xbc, 0xe0, 0xd4, 0xe4, 0x02,\n\t0x23, 0x53, 0xb3, 0x6c, 0x43, 0x01, 0x46, 0x21, 0x76, 0x2e, 0xe6, 0x60, 0x5f, 0x23, 0x01, 0x26,\n\t0xb8, 0x4a, 0x53, 0x43, 0x23, 0x01, 0x66, 0x2d, 0x69, 0x2e, 0xf6, 0x60, 0xa8, 0x11, 0xec, 0x5c,\n\t0xcc, 0x8e, 0xae, 0xc1, 0x02, 0x0c, 0x10, 0xa5, 0x26, 0x02, 0x8c, 0x5a, 0x36, 0x5c, 0x1c, 0x1e,\n\t0x89, 0xc5, 0x19, 0x60, 0x59, 0x2e, 0x2e, 0xb6, 0x60, 0x0f, 0x47, 0x88, 0xf1, 0xbc, 0x5c, 0x9c,\n\t0xde, 0xae, 0xce, 0xce, 0x8e, 0xde, 0x20, 0x2e, 0xd4, 0x68, 0x63, 0x88, 0xd1, 0xc1, 0x1e, 0x8e,\n\t0xc6, 0xf1, 0x20, 0x61, 0x66, 0x27, 0xef, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c,\n\t0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63,\n\t0x88, 0x32, 0x4c, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xf7, 0x74, 0x72,\n\t0x8c, 0xd0, 0xcd, 0xcc, 0xd7, 0x4f, 0xcf, 0xd7, 0xcd, 0x4c, 0x4a, 0xac, 0xd0, 0x2f, 0x48, 0x4c,\n\t0xce, 0x4e, 0x4c, 0x4f, 0x2d, 0xd6, 0x4f, 0xce, 0xcf, 0xcd, 0xcd, 0xcf, 0xd3, 0x87, 0xf8, 0x35,\n\t0x89, 0x0d, 0xec, 0x75, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4a, 0xcd, 0xcc, 0xc1, 0x0a,\n\t0x01, 0x00, 0x00,\n}\n"
  },
  {
    "path": "packages/common/crypto/crypto_test.go",
    "content": "package crypto\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n)\n\nfunc TestGetCryptoer(t *testing.T) {\n\tInitAsymAlgo(\"ECC_P256\")\n\tInitHashAlgo(\"SHA256\")\n\n\tsrc := []byte(\"Hello\")\n\tencodedStr := hex.EncodeToString(src)\n\tfmt.Println(\"Message in []byte: \", src)\n\tfmt.Printf(\"%s\\n\", encodedStr)\n\tprv, pub, err := GenKeyPair()\n\tif err != nil {\n\t\treturn\n\t}\n\tprvStr := hex.EncodeToString(prv)\n\tpubStr := hex.EncodeToString(pub)\n\tfmt.Println(\"privateKey is:\", prv, \"publicKey\", pub)\n\tfmt.Println(\"privateKeyString is:\", prvStr, \"publicKeyString is:\", pubStr)\n\taddr := Address(pub)\n\n\tfmt.Println(\"Address is:\", addr)\n\tsignedDataByte, err := Sign(prv, src)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tsignedDataStr := hex.EncodeToString(signedDataByte)\n\tfmt.Println(\"signedDataByte is:\", signedDataByte)\n\tfmt.Println(\"signedDataString is:\", signedDataStr)\n\n\t// priv test\n\t// signedDataString := \"3045022100929be5f360d10270bc67b6f9d28c47c257e472fdbdf66a3037022e47143bf94c0220246f9e378444d1d0fa81f613fb93c3c420e0a1abd0f3138cf10788492f690fc8\"\n\t// signedDataByte, err := hex.DecodeString(signedDataString)\n\t// if err != nil {\n\t// \tlog.Fatal(err)\n\t// }\n\t// pubString := \"7c66ce7703e6e4c4e31ba36c6eee29de345a8e9d36611f6bd2c809d3d0d47788fe3a66ab1970a8ea7d8b1f46e67956a481d638a0ab92a9aaaf0fbd2151af702e\"\n\t// pub, err := hex.DecodeString(pubString)\n\t// if err != nil {\n\t// \tlog.Fatal(err)\n\t// }\n\tfmt.Println(\"signedDataByPriv is:\", signedDataByte)\n\t//signature=3045022046468a5a6c62adff1d7c6a864dae3878a34f9d07be66b71f8ba34fc5a80d0e45022100caba64be8cf53709975a6a209c5c2197b01054f9b22edf25e99dfb8ea50a0633\n\t_, err = Verify(pub, src, signedDataByte)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n}\n"
  },
  {
    "path": "packages/common/crypto/ecies/ecccrypt.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage ecies\n\nimport (\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/big\"\n\t\"runtime\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n)\n\nfunc init() {\n\tlog.SetFlags(log.Ldate | log.Lshortfile)\n}\n\n//\n//Ecc\n/*func EccEnCrypt(plainText []byte,prv2 *ecies.PrivateKey)(crypText []byte,err error){\n\n\tct, err := ecies.Encrypt(rand.Reader, &prv2.PublicKey, plainText, nil, nil)\n\treturn ct, err\n}\n//\nfunc EccDeCrypt(cryptText []byte,prv2 *ecies.PrivateKey) ([]byte, error) {\n\tpt, err := prv2.Decrypt(cryptText, nil, nil)\n\treturn pt, err\n}*/\n\n//\nfunc EccPubEncrypt(plainText []byte, pub *ecdsa.PublicKey) (cryptText []byte, err error) { //\n\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase runtime.Error:\n\t\t\t\tlog.Println(\"runtime err:\", err, \"check key \")\n\t\t\tdefault:\n\t\t\t\tlog.Println(\"error:\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tpublicKey := ImportECDSAPublic(pub)\n\t//\n\tcrypttext, err := Encrypt(rand.Reader, publicKey, plainText, nil, nil)\n\n\treturn crypttext, err\n\n}\n\n//\nfunc EccPriDeCrypt(cryptText []byte, priv *ecdsa.PrivateKey) (msg []byte, err error) { //\n\tprivateKey := ImportECDSA(priv)\n\n\t//\n\tplainText, err := privateKey.Decrypt(cryptText, nil, nil)\n\n\treturn plainText, err\n}\n\nfunc EccCryptoKey(plainText []byte, publickey string) (cryptoText []byte, err error) {\n\tpubbuff, err := crypto.HexToPub(publickey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpub, err := GetPublicKeys(pubbuff)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn EccPubEncrypt(plainText, pub)\n}\n\nfunc EccDeCrypto(cryptoText []byte, prikey []byte) ([]byte, error) {\n\tpri, err := GetPrivateKeys(prikey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn EccPriDeCrypt(cryptoText, pri)\n}\n\n// GetPrivateKeys return\nfunc GetPrivateKeys(privateKey []byte) (ret *ecdsa.PrivateKey, err error) {\n\tvar pubkeyCurve elliptic.Curve\n\tpubkeyCurve = elliptic.P256()\n\tbi := new(big.Int).SetBytes(privateKey)\n\tpriv := new(ecdsa.PrivateKey)\n\tpriv.PublicKey.Curve = pubkeyCurve\n\tpriv.D = bi\n\treturn priv, nil\n}\n\n// GetPublicKeys return\nfunc GetPublicKeys(public []byte) (*ecdsa.PublicKey, error) {\n\tpubkey := new(ecdsa.PublicKey)\n\tif len(public) != consts.PubkeySizeLength {\n\t\treturn pubkey, fmt.Errorf(\"invalid parameters len(public) = %d\", len(public))\n\t}\n\n\tpubkey.Curve = elliptic.P256()\n\tpubkey.X = new(big.Int).SetBytes(public[0:consts.PrivkeyLength])\n\tpubkey.Y = new(big.Int).SetBytes(public[consts.PrivkeyLength:])\n\treturn pubkey, nil\n}\n"
  },
  {
    "path": "packages/common/crypto/ecies/ecies.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage ecies\n\nimport (\n\t\"crypto\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"crypto/subtle\"\n\t\"fmt\"\n\t\"hash\"\n\t\"io\"\n\t\"math/big\"\n)\n\nvar (\n\tErrImport                     = fmt.Errorf(\"ecies: failed to import key\")\n\tErrInvalidCurve               = fmt.Errorf(\"ecies: invalid elliptic curve\")\n\tErrInvalidParams              = fmt.Errorf(\"ecies: invalid ECIES parameters\")\n\tErrInvalidPublicKey           = fmt.Errorf(\"ecies: invalid public key\")\n\tErrSharedKeyIsPointAtInfinity = fmt.Errorf(\"ecies: shared key is point at infinity\")\n\tErrSharedKeyTooBig            = fmt.Errorf(\"ecies: shared key params are too big\")\n\tErrUnsupportedECIESParameters = fmt.Errorf(\"ecies: unsupported ECIES parameters\")\n)\n\n// PublicKey is a representation of an elliptic curve public key.\ntype PublicKey struct {\n\tX *big.Int\n\tY *big.Int\n\telliptic.Curve\n\tParams *ECIESParams\n}\n\n// Export an ECIES public key as an ECDSA public key.\nfunc (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {\n\treturn &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}\n}\n\n// Import an ECDSA public key as an ECIES public key.\nfunc ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {\n\treturn &PublicKey{\n\t\tX:      pub.X,\n\t\tY:      pub.Y,\n\t\tCurve:  pub.Curve,\n\t\tParams: ParamsFromCurve(pub.Curve),\n\t}\n}\n\n// PrivateKey is a representation of an elliptic curve private key.\ntype PrivateKey struct {\n\tPublicKey\n\tD *big.Int\n}\n\n// Export an ECIES private key as an ECDSA private key.\nfunc (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {\n\tpub := &prv.PublicKey\n\tpubECDSA := pub.ExportECDSA()\n\treturn &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D}\n}\n\n// Import an ECDSA private key as an ECIES private key.\nfunc ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {\n\tpub := ImportECDSAPublic(&prv.PublicKey)\n\treturn &PrivateKey{*pub, prv.D}\n}\n\n// Generate an elliptic curve public / private keypair. If params is nil,\n// the recommended default parameters for the key will be chosen.\nfunc GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {\n\tpb, x, y, err := elliptic.GenerateKey(curve, rand)\n\tif err != nil {\n\t\treturn\n\t}\n\tprv = new(PrivateKey)\n\tprv.PublicKey.X = x\n\tprv.PublicKey.Y = y\n\tprv.PublicKey.Curve = curve\n\tprv.D = new(big.Int).SetBytes(pb)\n\tif params == nil {\n\t\tparams = ParamsFromCurve(curve)\n\t}\n\tprv.PublicKey.Params = params\n\treturn\n}\n\n// MaxSharedKeyLength returns the maximum length of the shared key the\n// public key can produce.\nfunc MaxSharedKeyLength(pub *PublicKey) int {\n\treturn (pub.Curve.Params().BitSize + 7) / 8\n}\n\n// ECDH key agreement method used to establish secret keys for encryption.\nfunc (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {\n\tif prv.PublicKey.Curve != pub.Curve {\n\t\treturn nil, ErrInvalidCurve\n\t}\n\tif skLen+macLen > MaxSharedKeyLength(pub) {\n\t\treturn nil, ErrSharedKeyTooBig\n\t}\n\n\tx, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())\n\tif x == nil {\n\t\treturn nil, ErrSharedKeyIsPointAtInfinity\n\t}\n\n\tsk = make([]byte, skLen+macLen)\n\tskBytes := x.Bytes()\n\tcopy(sk[len(sk)-len(skBytes):], skBytes)\n\treturn sk, nil\n}\n\nvar (\n\tErrKeyDataTooLong = fmt.Errorf(\"ecies: can't supply requested key data\")\n\tErrSharedTooLong  = fmt.Errorf(\"ecies: shared secret is too long\")\n\tErrInvalidMessage = fmt.Errorf(\"ecies: invalid message\")\n)\n\nvar (\n\tbig2To32   = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil)\n\tbig2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1))\n)\n\nfunc incCounter(ctr []byte) {\n\tif ctr[3]++; ctr[3] != 0 {\n\t\treturn\n\t}\n\tif ctr[2]++; ctr[2] != 0 {\n\t\treturn\n\t}\n\tif ctr[1]++; ctr[1] != 0 {\n\t\treturn\n\t}\n\tif ctr[0]++; ctr[0] != 0 {\n\t\treturn\n\t}\n}\n\n// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).\nfunc concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) {\n\tif s1 == nil {\n\t\ts1 = make([]byte, 0)\n\t}\n\n\treps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8)\n\tif big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 {\n\t\tfmt.Println(big2To32M1)\n\t\treturn nil, ErrKeyDataTooLong\n\t}\n\n\tcounter := []byte{0, 0, 0, 1}\n\tk = make([]byte, 0)\n\n\tfor i := 0; i <= reps; i++ {\n\t\thash.Write(counter)\n\t\thash.Write(z)\n\t\thash.Write(s1)\n\t\tk = append(k, hash.Sum(nil)...)\n\t\thash.Reset()\n\t\tincCounter(counter)\n\t}\n\n\tk = k[:kdLen]\n\treturn\n}\n\n// messageTag computes the MAC of a message (called the tag) as per\n// SEC 1, 3.5.\nfunc messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {\n\tmac := hmac.New(hash, km)\n\tmac.Write(msg)\n\tmac.Write(shared)\n\ttag := mac.Sum(nil)\n\treturn tag\n}\n\n// Generate an initialisation vector for CTR mode.\nfunc generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {\n\tiv = make([]byte, params.BlockSize)\n\t_, err = io.ReadFull(rand, iv)\n\treturn\n}\n\n// symEncrypt carries out CTR encryption using the block cipher specified in the\n// parameters.\nfunc symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {\n\tc, err := params.Cipher(key)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tiv, err := generateIV(params, rand)\n\tif err != nil {\n\t\treturn\n\t}\n\tctr := cipher.NewCTR(c, iv)\n\n\tct = make([]byte, len(m)+params.BlockSize)\n\tcopy(ct, iv)\n\tctr.XORKeyStream(ct[params.BlockSize:], m)\n\treturn\n}\n\n// symDecrypt carries out CTR decryption using the block cipher specified in\n// the parameters\nfunc symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {\n\tc, err := params.Cipher(key)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tctr := cipher.NewCTR(c, ct[:params.BlockSize])\n\n\tm = make([]byte, len(ct)-params.BlockSize)\n\tctr.XORKeyStream(m, ct[params.BlockSize:])\n\treturn\n}\n\n// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1.\n//\n// s1 and s2 contain shared information that is not part of the resulting\n// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the\n// shared information parameters aren't being used, they should be nil.\nfunc Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {\n\tparams := pub.Params\n\tif params == nil {\n\t\tif params = ParamsFromCurve(pub.Curve); params == nil {\n\t\t\terr = ErrUnsupportedECIESParameters\n\t\t\treturn\n\t\t}\n\t}\n\tR, err := GenerateKey(rand, pub.Curve, params)\n\tif err != nil {\n\t\treturn\n\t}\n\n\thash := params.Hash()\n\tz, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)\n\tif err != nil {\n\t\treturn\n\t}\n\tK, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)\n\tif err != nil {\n\t\treturn\n\t}\n\tKe := K[:params.KeyLen]\n\tKm := K[params.KeyLen:]\n\thash.Write(Km)\n\tKm = hash.Sum(nil)\n\thash.Reset()\n\n\tem, err := symEncrypt(rand, params, Ke, m)\n\tif err != nil || len(em) <= params.BlockSize {\n\t\treturn\n\t}\n\n\td := messageTag(params.Hash, Km, em, s2)\n\n\tRb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)\n\tct = make([]byte, len(Rb)+len(em)+len(d))\n\tcopy(ct, Rb)\n\tcopy(ct[len(Rb):], em)\n\tcopy(ct[len(Rb)+len(em):], d)\n\treturn\n}\n\n// Decrypt decrypts an ECIES ciphertext.\nfunc (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {\n\tif len(c) == 0 {\n\t\treturn nil, ErrInvalidMessage\n\t}\n\tparams := prv.PublicKey.Params\n\tif params == nil {\n\t\tif params = ParamsFromCurve(prv.PublicKey.Curve); params == nil {\n\t\t\terr = ErrUnsupportedECIESParameters\n\t\t\treturn\n\t\t}\n\t}\n\thash := params.Hash()\n\n\tvar (\n\t\trLen   int\n\t\thLen   = hash.Size()\n\t\tmStart int\n\t\tmEnd   int\n\t)\n\n\tswitch c[0] {\n\tcase 2, 3, 4:\n\t\trLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4\n\t\tif len(c) < (rLen + hLen + 1) {\n\t\t\terr = ErrInvalidMessage\n\t\t\treturn\n\t\t}\n\tdefault:\n\t\terr = ErrInvalidPublicKey\n\t\treturn\n\t}\n\n\tmStart = rLen\n\tmEnd = len(c) - hLen\n\n\tR := new(PublicKey)\n\tR.Curve = prv.PublicKey.Curve\n\tR.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])\n\tif R.X == nil {\n\t\terr = ErrInvalidPublicKey\n\t\treturn\n\t}\n\tif !R.Curve.IsOnCurve(R.X, R.Y) {\n\t\terr = ErrInvalidCurve\n\t\treturn\n\t}\n\n\tz, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tK, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tKe := K[:params.KeyLen]\n\tKm := K[params.KeyLen:]\n\thash.Write(Km)\n\tKm = hash.Sum(nil)\n\thash.Reset()\n\n\td := messageTag(params.Hash, Km, c[mStart:mEnd], s2)\n\tif subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {\n\t\terr = ErrInvalidMessage\n\t\treturn\n\t}\n\n\tm, err = symDecrypt(params, Ke, c[mStart:mEnd])\n\treturn\n}\n\n//\nfunc ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {\n\treturn paramsFromCurve[curve]\n}\n\nvar paramsFromCurve = map[elliptic.Curve]*ECIESParams{\n\t//ethcrypto.S256(): ECIES_AES128_SHA256,\n\telliptic.P256(): ECIES_AES128_SHA256,\n\telliptic.P384(): ECIES_AES256_SHA384,\n\telliptic.P521(): ECIES_AES256_SHA512,\n}\nvar (\n\tECIES_AES128_SHA256 = &ECIESParams{\n\t\tHash:      sha256.New,\n\t\thashAlgo:  crypto.SHA256,\n\t\tCipher:    aes.NewCipher,\n\t\tBlockSize: aes.BlockSize,\n\t\tKeyLen:    16,\n\t}\n\n\tECIES_AES256_SHA256 = &ECIESParams{\n\t\tHash:      sha256.New,\n\t\thashAlgo:  crypto.SHA256,\n\t\tCipher:    aes.NewCipher,\n\t\tBlockSize: aes.BlockSize,\n\t\tKeyLen:    32,\n\t}\n\n\tECIES_AES256_SHA384 = &ECIESParams{\n\t\tHash:      sha512.New384,\n\t\thashAlgo:  crypto.SHA384,\n\t\tCipher:    aes.NewCipher,\n\t\tBlockSize: aes.BlockSize,\n\t\tKeyLen:    32,\n\t}\n\n\tECIES_AES256_SHA512 = &ECIESParams{\n\t\tHash:      sha512.New,\n\t\thashAlgo:  crypto.SHA512,\n\t\tCipher:    aes.NewCipher,\n\t\tBlockSize: aes.BlockSize,\n\t\tKeyLen:    32,\n\t}\n)\n\ntype ECIESParams struct {\n\tHash      func() hash.Hash // hash function\n\thashAlgo  crypto.Hash\n\tCipher    func([]byte) (cipher.Block, error) // symmetric cipher\n\tBlockSize int                                // block size of symmetric cipher\n\tKeyLen    int                                // length of symmetric key\n}\n"
  },
  {
    "path": "packages/common/crypto/hashalgo/hashalgo.go",
    "content": "package hashalgo\n"
  },
  {
    "path": "packages/common/crypto/hashalgo/keccak256.go",
    "content": "package hashalgo\n\nimport (\n\t\"crypto/hmac\"\n\t\"golang.org/x/crypto/sha3\"\n)\n\ntype Keccak256 struct{}\n\nfunc (k *Keccak256) GetHMAC(secret string, message string) ([]byte, error) {\n\tmac := hmac.New(sha3.NewLegacyKeccak256, []byte(secret))\n\tmac.Write([]byte(message))\n\treturn mac.Sum(nil), nil\n}\n\nfunc (k *Keccak256) GetHash(msg []byte) []byte {\n\treturn k.usingKeccak256(msg)\n}\n\nfunc (k *Keccak256) DoubleHash(msg []byte) []byte {\n\treturn k.usingKeccak256(k.usingKeccak256(msg))\n}\n\nfunc (k *Keccak256) usingKeccak256(data []byte) []byte {\n\td := sha3.NewLegacyKeccak256()\n\td.Write(data)\n\treturn d.Sum(nil)\n}\n"
  },
  {
    "path": "packages/common/crypto/hashalgo/sha256.go",
    "content": "package hashalgo\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n)\n\ntype SHA256 struct{}\n\nfunc (s *SHA256) GetHMAC(secret string, message string) ([]byte, error) {\n\tmac := hmac.New(sha256.New, []byte(secret))\n\tmac.Write([]byte(message))\n\treturn mac.Sum(nil), nil\n}\nfunc (s *SHA256) GetHash(msg []byte) []byte {\n\treturn s.usingSha256(msg)\n}\n\nfunc (s *SHA256) DoubleHash(msg []byte) []byte {\n\treturn s.usingSha256(s.usingSha256(msg))\n}\n\nfunc (s *SHA256) usingSha256(data []byte) []byte {\n\tout := sha256.Sum256(data)\n\treturn out[:]\n}\n"
  },
  {
    "path": "packages/common/crypto/hashalgo/sha3_256.go",
    "content": "package hashalgo\n\nimport (\n\t\"crypto/hmac\"\n\n\t\"golang.org/x/crypto/sha3\"\n)\n\ntype Sha3256 struct{}\n\nfunc (s *Sha3256) GetHMAC(secret string, message string) ([]byte, error) {\n\tmac := hmac.New(sha3.New256, []byte(secret))\n\tmac.Write([]byte(message))\n\treturn mac.Sum(nil), nil\n}\n\nfunc (s *Sha3256) GetHash(msg []byte) []byte {\n\treturn s.usingSha3(msg)\n}\n\nfunc (s *Sha3256) DoubleHash(msg []byte) []byte {\n\treturn s.usingSha3(s.usingSha3(msg))\n}\n\nfunc (s *Sha3256) usingSha3(data []byte) []byte {\n\thashed := sha3.Sum256(data)\n\treturn hashed[:]\n}\n"
  },
  {
    "path": "packages/common/crypto/hashalgo/sm3.go",
    "content": "package hashalgo\n\nimport (\n\t\"crypto/hmac\"\n\n\t\"github.com/tjfoc/gmsm/sm3\"\n)\n\ntype SM3 struct{}\n\nfunc (s *SM3) GetHMAC(secret string, message string) ([]byte, error) {\n\tmac := hmac.New(sm3.New, []byte(secret))\n\tmac.Write([]byte(message))\n\treturn mac.Sum(nil), nil\n}\n\nfunc (s *SM3) GetHash(msg []byte) []byte {\n\treturn s.usingSM3(msg)\n}\n\nfunc (s *SM3) DoubleHash(msg []byte) []byte {\n\treturn s.usingSM3(s.usingSM3(msg))\n}\n\nfunc (s *SM3) usingSM3(data []byte) []byte {\n\treturn sm3.Sm3Sum(data)\n}\n"
  },
  {
    "path": "packages/common/crypto/provider.go",
    "content": "package crypto\n\ntype AsymProvider interface {\n\tGenKeyPair() ([]byte, []byte, error)\n\tSign(privateKey, hash []byte) ([]byte, error)\n\t// Verify checks if forSign has been signed with corresponding to public the private key\n\tVerify(public, hash, sign []byte) (bool, error)\n\tPrivateToPublic(key []byte) ([]byte, error)\n}\n\ntype HashProvider interface {\n\t// GetHMAC returns HMAC hash\n\tGetHMAC(secret string, msg string) ([]byte, error)\n\t// GetHash returns hash of passed bytes\n\tGetHash(msg []byte) []byte\n\t// DoubleHash returns double hash of passed bytes\n\tDoubleHash(msg []byte) []byte\n}\n"
  },
  {
    "path": "packages/common/crypto/random.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage crypto\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n)\n\n// RandSeq is returning random string\nfunc RandSeq(n int) string {\n\tvar letters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\")\n\trand.Seed(time.Now().UnixNano())\n\tb := make([]rune, n)\n\tfor i := range b {\n\t\tb[i] = letters[rand.Intn(len(letters))]\n\t}\n\treturn string(b)\n}\n"
  },
  {
    "path": "packages/common/crypto/symalgo/aes/aes.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage aes\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\tcrand \"crypto/rand\"\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n)\n\n// Encrypt is encrypting\nfunc Encrypt(msg []byte, key []byte, iv []byte) ([]byte, error) {\n\treturn encryptCBC(msg, key, iv)\n}\n\n// Decrypt is decrypting\nfunc Decrypt(msg []byte, key []byte, iv []byte) ([]byte, error) {\n\treturn decryptCBC(msg, key, iv)\n}\n\n// SharedEncrypt creates a shared key and encrypts text. The first 32 characters are the created public key.\n// The cipher text can be only decrypted with the original private key.\n//func SharedEncrypt(public, text []byte) ([]byte, error) {\n//\tpriv, pub, err := genBytesKeys()\n//\tif err != nil {\n//\t\treturn nil, err\n//\t}\n//\tshared, err := getSharedKey(priv, public)\n//\tif err != nil {\n//\t\treturn nil, err\n//\t}\n//\tval, err := Encrypt(shared, text, pub)\n//\treturn val, err\n//}\n\n// CBCEncrypt encrypts the text by using the key parameter. It uses CBC mode of AES.\nfunc encryptCBC(text, key, iv []byte) ([]byte, error) {\n\tif iv == nil {\n\t\tiv = make([]byte, consts.BlockSize)\n\t\tif _, err := crand.Read(iv); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else if len(iv) < consts.BlockSize {\n\t\treturn nil, fmt.Errorf(`wrong size of iv %d`, len(iv))\n\t} else if len(iv) > consts.BlockSize {\n\t\tiv = iv[:consts.BlockSize]\n\t}\n\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tplaintext := pKCS7Padding(text, consts.BlockSize)\n\tmode := cipher.NewCBCEncrypter(block, iv)\n\tencrypted := make([]byte, len(plaintext))\n\tmode.CryptBlocks(encrypted, plaintext)\n\treturn append(iv, encrypted...), nil\n\n}\n\n// CBCDecrypt decrypts the text by using key. It uses CBC mode of AES.\nfunc decryptCBC(ciphertext, key, iv []byte) ([]byte, error) {\n\tif iv == nil {\n\t\tiv = ciphertext[:consts.BlockSize]\n\t\tciphertext = ciphertext[consts.BlockSize:]\n\t}\n\tif len(ciphertext) < consts.BlockSize || len(ciphertext)%consts.BlockSize != 0 {\n\t\treturn nil, fmt.Errorf(`wrong size of cipher %d`, len(ciphertext))\n\t}\n\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := make([]byte, len(ciphertext))\n\tcipher.NewCBCDecrypter(block, iv[:consts.BlockSize]).CryptBlocks(ret, ciphertext)\n\tif ret, err = pKCS7UnPadding(ret); err != nil {\n\t\treturn nil, err\n\t}\n\treturn ret, nil\n\n}\n\n// pKCS7Padding realizes PKCS#7 encoding which is described in RFC 5652.\nfunc pKCS7Padding(src []byte, blockSize int) []byte {\n\tpadding := blockSize - len(src)%blockSize\n\treturn append(src, bytes.Repeat([]byte{byte(padding)}, padding)...)\n}\n\n// pKCS7UnPadding realizes PKCS#7 decoding.\nfunc pKCS7UnPadding(src []byte) ([]byte, error) {\n\tlength := len(src)\n\tpadLength := int(src[length-1])\n\tfor i := length - padLength; i < length; i++ {\n\t\tif int(src[i]) != padLength {\n\t\t\treturn nil, fmt.Errorf(`incorrect input of PKCS7UnPadding`)\n\t\t}\n\t}\n\treturn src[:length-int(src[length-1])], nil\n}\nfunc PKCS5Padding(ciphertext []byte, blockSize int) []byte {\n\tpadding := blockSize - len(ciphertext)%blockSize\n\tpadtext := bytes.Repeat([]byte{byte(padding)}, padding)\n\treturn append(ciphertext, padtext...)\n}\n\nfunc PKCS5UnPadding(origData []byte) []byte {\n\tlength := len(origData)\n\tunpadding := int(origData[length-1])\n\treturn origData[:(length - unpadding)]\n}\n\nfunc AesEncrypt(origData, key []byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tblockSize := block.BlockSize()\n\torigData = PKCS5Padding(origData, blockSize)\n\tblockMode := cipher.NewCBCEncrypter(block, key[:blockSize])\n\tcrypted := make([]byte, len(origData))\n\tblockMode.CryptBlocks(crypted, origData)\n\treturn crypted, nil\n}\n\nfunc AesDecrypt(crypted, key []byte) ([]byte, error) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tblockSize := block.BlockSize()\n\tblockMode := cipher.NewCBCDecrypter(block, key[:blockSize])\n\torigData := make([]byte, len(crypted))\n\tblockMode.CryptBlocks(origData, crypted)\n\torigData = PKCS5UnPadding(origData)\n\treturn origData, nil\n}\n"
  },
  {
    "path": "packages/common/crypto/symalgo/aes/aes_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage aes\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestAesEncryptAndDecrypt(t *testing.T) {\n\tvar aeskey = []byte(\"123456789012345612345678\") // AES-128(16bytes) AES-256(32bytes)\n\tpass := []byte(\"This is my private data!\")\n\tfmt.Printf(\"password:%v\\n\", string(aeskey))\n\tfmt.Printf(\"src data:%v\\n\", string(pass))\n\n\txpass, err := AesEncrypt(pass, aeskey)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tpass64 := base64.StdEncoding.EncodeToString(xpass)\n\tfmt.Printf(\"encode:%v\\n\", pass64)\n\n\tbytesPass, err := base64.StdEncoding.DecodeString(pass64)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\ttpass, err := AesDecrypt(bytesPass, aeskey)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\tfmt.Printf(\"aesdecrypt:%s\\n\", tpass)\n}\n"
  },
  {
    "path": "packages/common/crypto/x509/cert.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage x509\n\nimport (\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n)\n\nvar (\n\terrParseCert     = errors.New(\"Failed to parse certificate\")\n\terrParseRootCert = errors.New(\"Failed to parse root certificate\")\n)\n\ntype Cert struct {\n\tcert *x509.Certificate\n}\n\nfunc (c *Cert) Validate(pem []byte) error {\n\troots := x509.NewCertPool()\n\tif ok := roots.AppendCertsFromPEM(pem); !ok {\n\t\treturn errParseRootCert\n\t}\n\n\tif _, err := c.cert.Verify(x509.VerifyOptions{Roots: roots}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *Cert) EqualBytes(bs ...[]byte) bool {\n\tfor _, b := range bs {\n\t\tother, err := parseCert(b)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tif c.cert.Equal(other) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc parseCert(b []byte) (*x509.Certificate, error) {\n\tblock, _ := pem.Decode(b)\n\tif block == nil {\n\t\treturn nil, errParseCert\n\t}\n\n\tcert, err := x509.ParseCertificate(block.Bytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn cert, nil\n}\n\nfunc ParseCert(b []byte) (c *Cert, err error) {\n\tcert, err := parseCert(b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Cert{cert}, nil\n}\n"
  },
  {
    "path": "packages/common/log/filename_hook.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage log\n\nimport (\n\t\"path\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// ContextHook storing nothing but behavior\ntype ContextHook struct{}\n\n// Levels returns all log levels\nfunc (hook ContextHook) Levels() []logrus.Level {\n\treturn logrus.AllLevels\n}\n\n// Fire the log entry\nfunc (hook ContextHook) Fire(entry *logrus.Entry) error {\n\tvar pc []uintptr\n\tif _, skip := entry.Data[\"nocontext\"]; skip {\n\t\tdelete(entry.Data, \"nocontext\")\n\t\treturn nil\n\t}\n\tif conf.Config.Log.LogLevel == \"DEBUG\" {\n\t\tpc = make([]uintptr, 15, 15)\n\t} else {\n\t\tpc = make([]uintptr, 4, 4)\n\t}\n\tcnt := runtime.Callers(6, pc)\n\n\tcount := 0\n\tfor i := 0; i < cnt; i++ {\n\t\tfu := runtime.FuncForPC(pc[i] - 1)\n\t\tname := fu.Name()\n\t\tif !strings.Contains(name, \"github.com/sirupsen/logrus\") {\n\t\t\tfile, line := fu.FileLine(pc[i] - 1)\n\t\t\tif count == 0 {\n\t\t\t\tentry.Data[\"file\"] = path.Base(file)\n\t\t\t\tentry.Data[\"func\"] = path.Base(name)\n\t\t\t\tentry.Data[\"line\"] = line\n\t\t\t\tentry.Data[\"time\"] = time.Now().Format(time.RFC3339)\n\t\t\t\tif conf.Config.Log.LogLevel != \"DEBUG\" {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif count >= 1 {\n\t\t\t\tif count == 1 {\n\t\t\t\t\tentry.Data[\"from\"] = []string{}\n\t\t\t\t}\n\t\t\t\tentry.Data[\"from\"] = append(entry.Data[\"from\"].([]string), path.Base(name))\n\t\t\t}\n\t\t\tcount += 1\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/common/log/hex_hook.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage log\n\nimport (\n\t\"encoding/hex\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\ntype HexHook struct{}\n\n// Levels returns all log levels\nfunc (hook HexHook) Levels() []logrus.Level {\n\treturn logrus.AllLevels\n}\n\n// Fire the log entry\nfunc (hook HexHook) Fire(entry *logrus.Entry) error {\n\tfor i := range entry.Data {\n\t\tif b, ok := entry.Data[i].([]byte); ok {\n\t\t\tentry.Data[i] = hex.EncodeToString(b)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/common/log/syslog_hook.go",
    "content": "//go:build !windows && !nacl && !plan9\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage log\n\nimport (\n\t\"log/syslog\"\n\n\tlSyslog \"github.com/sirupsen/logrus/hooks/syslog\"\n)\n\nvar SyslogFacilityPriority map[string]syslog.Priority\n\nfunc init() {\n\tSyslogFacilityPriority = map[string]syslog.Priority{\n\t\t\"kern\":     syslog.LOG_KERN,\n\t\t\"user\":     syslog.LOG_USER,\n\t\t\"mail\":     syslog.LOG_MAIL,\n\t\t\"daemon\":   syslog.LOG_DAEMON,\n\t\t\"auth\":     syslog.LOG_AUTH,\n\t\t\"syslog\":   syslog.LOG_SYSLOG,\n\t\t\"lpr\":      syslog.LOG_LPR,\n\t\t\"news\":     syslog.LOG_NEWS,\n\t\t\"uucp\":     syslog.LOG_UUCP,\n\t\t\"cron\":     syslog.LOG_CRON,\n\t\t\"authpriv\": syslog.LOG_AUTHPRIV,\n\t\t\"ftp\":      syslog.LOG_FTP,\n\t\t\"local0\":   syslog.LOG_LOCAL0,\n\t\t\"local1\":   syslog.LOG_LOCAL1,\n\t\t\"local2\":   syslog.LOG_LOCAL2,\n\t\t\"local3\":   syslog.LOG_LOCAL3,\n\t\t\"local4\":   syslog.LOG_LOCAL4,\n\t\t\"local5\":   syslog.LOG_LOCAL5,\n\t\t\"local6\":   syslog.LOG_LOCAL6,\n\t\t\"local7\":   syslog.LOG_LOCAL7,\n\t}\n}\n\nfunc NewSyslogHook(priority string, tag string) (*lSyslog.SyslogHook, error) {\n\treturn lSyslog.NewSyslogHook(\"\", \"\", SyslogFacilityPriority[priority], tag)\n}\n"
  },
  {
    "path": "packages/common/log/syslog_hook_windows.go",
    "content": "//go:build windows\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage log\n\nimport (\n\t\"github.com/sirupsen/logrus\"\n)\n\n// SyslogHook to send logs via syslog.\ntype SyslogHook struct {\n\tSyslogNetwork string\n\tSyslogRaddr   string\n}\n\nfunc NewSyslogHook(appName, facility string) (*SyslogHook, error) {\n\treturn &SyslogHook{\"\", \"localhost\"}, nil\n}\n\nfunc (hook *SyslogHook) Fire(entry *logrus.Entry) error {\n\treturn nil\n}\n\nfunc (hook *SyslogHook) Levels() []logrus.Level {\n\treturn logrus.AllLevels\n}\n"
  },
  {
    "path": "packages/common/random/rand.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage random\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n)\n\ntype Rand struct {\n\tsrc *rand.Rand\n}\n\nfunc (r *Rand) BytesSeed(b []byte) *rand.Rand {\n\tseed := crypto.CalcChecksum(b)\n\tr.src.Seed(int64(seed))\n\treturn r.src\n}\n\nfunc NewRand(seed int64) *Rand {\n\treturn &Rand{\n\t\tsrc: rand.New(rand.NewSource(seed)),\n\t}\n}\n\nfunc RandInt(min, max int) int {\n\tif min >= max || min == 0 || max == 0 {\n\t\treturn max\n\t}\n\treturn rand.Intn(max-min) + min\n}\n\nconst (\n\tKC_RAND_KIND_NUM   = 0 // number\n\tKC_RAND_KIND_LOWER = 1 //\n\tKC_RAND_KIND_UPPER = 2 //\n\tKC_RAND_KIND_ALL   = 3 //\n)\n\n//\nfunc Krand(size int64, kind int) []byte {\n\tikind, kinds, result := kind, [][]int{{10, 48}, {26, 97}, {26, 65}}, make([]byte, size)\n\tis_all := kind > 2 || kind < 0\n\trand.Seed(time.Now().UnixNano())\n\tfor i := 0; i < int(size); i++ {\n\t\tif is_all { // random ikind\n\t\t\tikind = rand.Intn(3)\n\t\t}\n\t\tscope, base := kinds[ikind][0], kinds[ikind][1]\n\t\tresult[i] = uint8(base + rand.Intn(scope))\n\t}\n\treturn result\n}\n\n//\nfunc RandNumber(size int64) string {\n\tresult := Krand(size, KC_RAND_KIND_ALL)\n\treturn string(result[:])\n}\n"
  },
  {
    "path": "packages/common/random/rand_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage random\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRand(t *testing.T) {\n\tcases := [][]int64{\n\t\t{3434102771992637744, 1523931518789473682},\n\t\t{3434102771992637744, 1523931518789473682},\n\t}\n\n\trand := NewRand(0)\n\tfor _, values := range cases {\n\t\tr := rand.BytesSeed([]byte(\"reset\"))\n\t\tfor _, v := range values {\n\t\t\tassert.Equal(t, v, r.Int63())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/common/size.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage common\n\nimport (\n\t\"fmt\"\n)\n\n// StorageSize is a wrapper around a float value that supports user friendly\n// formatting.\ntype StorageSize float64\n\n// String implements the stringer interface.\nfunc (s StorageSize) String() string {\n\tif s > 1099511627776 {\n\t\treturn fmt.Sprintf(\"%.2f TiB\", s/1099511627776)\n\t} else if s > 1073741824 {\n\t\treturn fmt.Sprintf(\"%.2f GiB\", s/1073741824)\n\t} else if s > 1048576 {\n\t\treturn fmt.Sprintf(\"%.2f MiB\", s/1048576)\n\t} else if s > 1024 {\n\t\treturn fmt.Sprintf(\"%.2f KiB\", s/1024)\n\t} else {\n\t\treturn fmt.Sprintf(\"%.2f B\", s)\n\t}\n}\n\n// TerminalString implements log.TerminalStringer, formatting a string for console\n// output during logging.\nfunc (s StorageSize) TerminalString() string {\n\tif s > 1099511627776 {\n\t\treturn fmt.Sprintf(\"%.2fTiB\", s/1099511627776)\n\t} else if s > 1073741824 {\n\t\treturn fmt.Sprintf(\"%.2fGiB\", s/1073741824)\n\t} else if s > 1048576 {\n\t\treturn fmt.Sprintf(\"%.2fMiB\", s/1048576)\n\t} else if s > 1024 {\n\t\treturn fmt.Sprintf(\"%.2fKiB\", s/1024)\n\t} else {\n\t\treturn fmt.Sprintf(\"%.2fB\", s)\n\t}\n}\n"
  },
  {
    "path": "packages/conf/conf.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage conf\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/BurntSushi/toml\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/viper\"\n)\n\n// Config global parameters\nvar Config GlobalConfig\n\n// Str converts HostPort pair to string format\nfunc (h HostPort) Str() string {\n\treturn fmt.Sprintf(\"%s:%d\", h.Host, h.Port)\n}\n\n// GetPidPath returns path to pid file\nfunc (c *GlobalConfig) GetPidPath() string {\n\treturn c.DirPathConf.PidFilePath\n}\n\n// LoadConfig from configFile\n// the function has side effect updating global var Config\nfunc LoadConfig(path string) error {\n\terr := LoadConfigToVar(path, &Config)\n\tif err != nil {\n\t\tlog.WithError(err).Fatal(\"Loading config\")\n\t}\n\tlog.WithFields(log.Fields{\"path\": path}).Info(\"Loading config\")\n\tregisterCrypto(Config.CryptoSettings)\n\treturn nil\n}\n\nfunc LoadConfigToVar(path string, v *GlobalConfig) error {\n\t_, err := os.Stat(path)\n\tif os.IsNotExist(err) {\n\t\treturn errors.Errorf(\"Unable to load config file %s\", path)\n\t}\n\n\tviper.SetConfigFile(path)\n\terr = viper.ReadInConfig()\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"reading config\")\n\t}\n\n\terr = viper.Unmarshal(v)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"marshalling config to global struct variable\")\n\t}\n\treturn nil\n}\n\n// GetConfigFromPath read config from path and returns GlobalConfig struct\nfunc GetConfigFromPath(path string) (*GlobalConfig, error) {\n\tlog.WithFields(log.Fields{\"path\": path}).Info(\"Loading clb config\")\n\n\t_, err := os.Stat(path)\n\tif os.IsNotExist(err) {\n\t\treturn nil, errors.Errorf(\"Unable to load config file %s\", path)\n\t}\n\n\tviper.SetConfigFile(path)\n\terr = viper.ReadInConfig()\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"reading config\")\n\t}\n\n\tc := &GlobalConfig{}\n\terr = viper.Unmarshal(c)\n\tif err != nil {\n\t\treturn c, errors.Wrapf(err, \"marshalling config to global struct variable\")\n\t}\n\n\treturn c, nil\n}\n\n// SaveConfig save global parameters to configFile\nfunc SaveConfig(path string) error {\n\tdir := filepath.Dir(path)\n\tif _, err := os.Stat(dir); os.IsNotExist(err) {\n\t\terr := os.Mkdir(dir, 0775)\n\t\tif err != nil {\n\t\t\treturn errors.Wrapf(err, \"creating dir %s\", dir)\n\t\t}\n\t}\n\n\tcf, err := os.Create(path)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"Create config file failed\")\n\t\treturn err\n\t}\n\tdefer cf.Close()\n\n\terr = toml.NewEncoder(cf).Encode(Config)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// FillRuntimePaths fills paths from runtime parameters\nfunc FillRuntimePaths() error {\n\tif Config.DirPathConf.DataDir == \"\" {\n\t\t//cwd, err := os.Getwd()\n\t\t//if err != nil {\n\t\t//\treturn errors.Wrapf(err, \"getting current wd\")\n\t\t//}\n\n\t\t//Config.DataDir = filepath.Join(cwd, consts.DefaultWorkdirName)\n\t\tConfig.DirPathConf.DataDir = filepath.Join(consts.DefaultWorkdirName)\n\t}\n\n\tif Config.DirPathConf.KeysDir == \"\" {\n\t\tConfig.DirPathConf.KeysDir = Config.DirPathConf.DataDir\n\t}\n\n\tif Config.DirPathConf.TempDir == \"\" {\n\t\tConfig.DirPathConf.TempDir = filepath.Join(os.TempDir(), consts.DefaultTempDirName)\n\t}\n\n\tif Config.DirPathConf.FirstBlockPath == \"\" {\n\t\tConfig.DirPathConf.FirstBlockPath = filepath.Join(Config.DirPathConf.DataDir, consts.FirstBlockFilename)\n\t}\n\n\tif Config.DirPathConf.PidFilePath == \"\" {\n\t\tConfig.DirPathConf.PidFilePath = filepath.Join(Config.DirPathConf.DataDir, consts.DefaultPidFilename)\n\t}\n\n\tif Config.DirPathConf.LockFilePath == \"\" {\n\t\tConfig.DirPathConf.LockFilePath = filepath.Join(Config.DirPathConf.DataDir, consts.DefaultLockFilename)\n\t}\n\n\treturn nil\n}\n\n// FillRuntimeKey fills parameters of keys from runtime parameters\nfunc FillRuntimeKey() error {\n\tkeyIDFileName := filepath.Join(Config.DirPathConf.KeysDir, consts.KeyIDFilename)\n\tkeyIDBytes, err := os.ReadFile(keyIDFileName)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"path\": keyIDFileName}).Error(\"reading KeyID file\")\n\t\treturn err\n\t}\n\n\tConfig.KeyID, err = strconv.ParseInt(string(keyIDBytes), 10, 64)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err, \"value\": string(keyIDBytes)}).Error(\"converting keyID to int\")\n\t\treturn errors.New(\"converting keyID to int\")\n\t}\n\n\treturn nil\n}\n\n// GetNodesAddr returns address of nodes\nfunc GetNodesAddr() []string {\n\treturn Config.BootNodes.NodesAddr[:]\n}\n\nfunc registerCrypto(c CryptoSettings) {\n\tcrypto.InitAsymAlgo(c.Cryptoer)\n\tcrypto.InitHashAlgo(c.Hasher)\n}\n"
  },
  {
    "path": "packages/conf/runmode.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage conf\n\ntype RunMode string\n\nconst (\n\t// running mode\n\tnode      RunMode = \"NONE\"\n\tclbMaster RunMode = \"CLBMaster\"\n\tclb       RunMode = \"CLB\"\n\tsubNode   RunMode = \"SubNode\"\n)\n\n// IsCLBMaster returns true if mode equal clbMaster\nfunc (rm RunMode) IsCLBMaster() bool {\n\treturn rm == clbMaster\n}\n\n// IsCLB returns true if mode equal clb\nfunc (rm RunMode) IsCLB() bool {\n\treturn rm == clb\n}\n\n// IsNode returns true if mode not equal to any CLB\nfunc (rm RunMode) IsNode() bool {\n\treturn rm == node\n}\n\n// IsSupportingCLB returns true if mode support clb\nfunc (rm RunMode) IsSupportingCLB() bool {\n\treturn rm.IsCLB() || rm.IsCLBMaster()\n}\n\nfunc (rm RunMode) IsSubNode() bool {\n\treturn rm == subNode\n}\n\n// IsCLB check running mode\nfunc (c GlobalConfig) IsCLB() bool {\n\treturn RunMode(c.LocalConf.RunNodeMode).IsCLB()\n}\n\n// IsCLBMaster check running mode\nfunc (c GlobalConfig) IsCLBMaster() bool {\n\treturn RunMode(c.LocalConf.RunNodeMode).IsCLBMaster()\n}\n\n// IsSupportingCLB check running mode\nfunc (c GlobalConfig) IsSupportingCLB() bool {\n\treturn RunMode(c.LocalConf.RunNodeMode).IsSupportingCLB()\n}\n\n// IsNode check running mode\nfunc (c GlobalConfig) IsNode() bool {\n\treturn RunMode(c.LocalConf.RunNodeMode).IsNode()\n}\n\n// IsSubNode check running mode\nfunc (c GlobalConfig) IsSubNode() bool {\n\treturn RunMode(c.LocalConf.RunNodeMode).IsSubNode()\n}\n"
  },
  {
    "path": "packages/conf/syspar/honornode.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage syspar\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst publicKeyLength = 64\n\nvar (\n\terrHonorNodeInvalidValues       = errors.New(\"invalid values of the honor_nodes parameter\")\n\terrHonorNodeDuplicatePublicKey  = errors.New(\"duplicate publicKey values of the honor_nodes parameter\")\n\terrHonorNodeDuplicateAPIAddress = errors.New(\"duplicate api address values of the honor_nodes parameter\")\n\terrHonorNodeDuplicateTCPAddress = errors.New(\"duplicate tcp address values of the honor_nodes parameter\")\n)\n\ntype honorNodeJSON struct {\n\tTCPAddress string      `json:\"tcp_address\"`\n\tAPIAddress string      `json:\"api_address\"`\n\tPublicKey  string      `json:\"public_key\"`\n\tUnbanTime  json.Number `json:\"unban_time,er\"`\n\tStopped    bool        `json:\"stopped\"`\n}\n\n// HonorNode is storing honor node data\ntype HonorNode struct {\n\tTCPAddress string\n\tAPIAddress string\n\tPublicKey  []byte\n\tUnbanTime  time.Time\n\tStopped    bool\n}\n\n// UnmarshalJSON is custom json unmarshaller\nfunc (fn *HonorNode) UnmarshalJSON(b []byte) (err error) {\n\tdata := honorNodeJSON{}\n\tif err = json.Unmarshal(b, &data); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err, \"value\": string(b)}).Error(\"Unmarshalling honor nodes to json\")\n\t\treturn err\n\t}\n\n\tfn.TCPAddress = data.TCPAddress\n\tfn.APIAddress = data.APIAddress\n\tfn.Stopped = data.Stopped\n\tif fn.PublicKey, err = crypto.HexToPub(data.PublicKey); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err, \"value\": data.PublicKey}).Error(\"converting honor nodes public key from hex\")\n\t\treturn err\n\t}\n\tfn.UnbanTime = time.Unix(converter.StrToInt64(data.UnbanTime.String()), 0)\n\n\tif err = fn.Validate(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (fn *HonorNode) MarshalJSON() ([]byte, error) {\n\tjfn := honorNodeJSON{\n\t\tTCPAddress: fn.TCPAddress,\n\t\tAPIAddress: fn.APIAddress,\n\t\tPublicKey:  crypto.PubToHex(fn.PublicKey),\n\t\tUnbanTime:  json.Number(strconv.FormatInt(fn.UnbanTime.Unix(), 10)),\n\t}\n\n\tdata, err := json.Marshal(jfn)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"Marshalling honor nodes to json\")\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\n// ValidateURL returns error if the URL is invalid\nfunc validateURL(rawurl string) error {\n\tu, err := url.ParseRequestURI(rawurl)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(u.Scheme) == 0 {\n\t\treturn fmt.Errorf(\"invalid scheme: %s\", rawurl)\n\t}\n\n\tif len(u.Host) == 0 {\n\t\treturn fmt.Errorf(\"invalid host: %s\", rawurl)\n\t}\n\n\treturn nil\n}\n\n// Validate checks values\nfunc (fn *HonorNode) Validate() error {\n\tif len(fn.PublicKey) !=\n\t\tpublicKeyLength || len(fn.TCPAddress) == 0 {\n\t\treturn errHonorNodeInvalidValues\n\t}\n\n\tif err := validateURL(fn.APIAddress); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc DuplicateHonorNode(fn []*HonorNode) error {\n\tn := len(fn)\n\tvar dup error\n\tfor i := 0; i < n; i++ {\n\t\tfor j := i + 1; j < n; j++ {\n\t\t\tif j > 0 && reflect.DeepEqual(fn[i].PublicKey, fn[j].PublicKey) {\n\t\t\t\tdup = errHonorNodeDuplicatePublicKey\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif j > 0 && reflect.DeepEqual(fn[i].APIAddress, fn[j].APIAddress) {\n\t\t\t\tdup = errHonorNodeDuplicateAPIAddress\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif j > 0 && reflect.DeepEqual(fn[i].TCPAddress, fn[j].TCPAddress) {\n\t\t\t\tdup = errHonorNodeDuplicateTCPAddress\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif vali := fn[i].Validate(); vali != nil {\n\t\t\treturn vali\n\t\t}\n\t}\n\treturn dup\n}\n"
  },
  {
    "path": "packages/conf/syspar/honornode_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage syspar\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestHonorNode(t *testing.T) {\n\tcases := []struct {\n\t\tvalue,\n\t\terr string\n\t\tformattingErr bool\n\t}{\n\t\t{value: `[{\"tcp_address\":\"127.0.0.1\", \"api_address\":\"https://127.0.0.1\", \"key_id\":\"100\", \"public_key\":\"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\", \"unban_time\": 111111}]`, err: ``},\n\t\t{value: `[{\"tcp_address\":\"\", \"api_address\":\"https://127.0.0.1\", \"key_id\":\"100\", \"public_key\":\"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\", \"unban_time\": 111111}]`, err: `Invalid values of the honor_nodes parameter`},\n\t\t{value: `[{\"tcp_address\":\"127.0.0.1\", \"api_address\":\"127.0.0.1\", \"key_id\":\"100\", \"public_key\":\"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\", \"unban_time\": 111111}]`, err: `parse 127.0.0.1: invalid URI for request`},\n\t\t{value: `[{\"tcp_address\":\"127.0.0.1\", \"api_address\":\"https://\", \"key_id\":\"100\", \"public_key\":\"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\", \"unban_time\": 111111}]`, err: `Invalid host: https://`},\n\t\t{value: `[{\"tcp_address\":\"127.0.0.1\", \"api_address\":\"https://127.0.0.1\", \"key_id\":\"0\", \"public_key\":\"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d0\", \"unban_time\": 111111}]`, err: `Invalid values of the honor_nodes parameter`},\n\t\t{value: `[{\"tcp_address\":\"127.0.0.1\", \"api_address\":\"https://127.0.0.1\", \"key_id\":\"100\", \"public_key\":\"c1a9e7b2fb8cea2a272e183c3e27e2d59a3ebe613f51873a46885c9201160bd263ef43b583b631edd1284ab42483712fd2ccc40864fe9368115ceeee47a7c7d00000000000\", \"unban_time\": 111111}]`, err: `Invalid values of the honor_nodes parameter`},\n\t\t{value: `[{}}]`, err: `invalid character '}' after array element`, formattingErr: true},\n\t}\n\tfor _, v := range cases {\n\t\t// Testing Unmarshalling string -> struct\n\t\tvar fs []*HonorNode\n\t\terr := json.Unmarshal([]byte(v.value), &fs)\n\t\tif len(v.err) == 0 {\n\t\t\tassert.NoError(t, err)\n\t\t} else {\n\t\t\tassert.EqualError(t, err, v.err)\n\t\t}\n\n\t\t// Testing Marshalling struct -> string\n\t\tblah, err := json.Marshal(fs)\n\t\trequire.NoError(t, err)\n\n\t\t// Testing Unmarshaling string (from struct) -> struct\n\t\tvar unfs []HonorNode\n\t\terr = json.Unmarshal(blah, &unfs)\n\t\tif !v.formattingErr && len(v.err) != 0 {\n\t\t\tassert.EqualError(t, err, v.err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/conf/syspar/syspar.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage syspar\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\t// NumberNodes is the number of nodes\n\tNumberNodes = `number_of_nodes`\n\t// FuelRate is the rate\n\tFuelRate = `fuel_rate`\n\t// HonorNodes is the list of nodes\n\tHonorNodes = `honor_nodes`\n\t// GapsBetweenBlocks is the time between blocks\n\tGapsBetweenBlocks = `gap_between_blocks`\n\t// MaxBlockSize is the maximum size of the block\n\tMaxBlockSize = `max_block_size`\n\t// MaxTxSize is the maximum size of the transaction\n\tMaxTxSize = `max_tx_size`\n\t// MaxForsignSize is the maximum size of the forsign of transaction\n\tMaxForsignSize = `max_forsign_size`\n\t// MaxBlockFuel is the maximum fuel of the block\n\tMaxBlockFuel = `max_fuel_block`\n\t// MaxTxFuel is the maximum fuel of the transaction\n\tMaxTxFuel = `max_fuel_tx`\n\t// MaxTxCount is the maximum count of the transactions\n\tMaxTxCount = `max_tx_block`\n\t// MaxBlockGenerationTime is the time limit for block generation (in ms)\n\tMaxBlockGenerationTime = `max_block_generation_time`\n\t// MaxColumns is the maximum columns in tables\n\tMaxColumns = `max_columns`\n\t// MaxIndexes is the maximum indexes in tables\n\tMaxIndexes = `max_indexes`\n\t// MaxBlockUserTx is the maximum number of user's transactions in one block\n\tMaxBlockUserTx = `max_tx_block_per_user`\n\t// SizeFuel is the fuel cost of 1024 bytes of the transaction data\n\tSizeFuel = `price_tx_data`\n\t// TaxesWallet is the address for taxess\n\tTaxesWallet = `taxes_wallet`\n\t// RbBlocks1 rollback from queue_bocks\n\tRbBlocks1 = `rollback_blocks`\n\t// BlockReward value of reward, which is chrged on block generation\n\tBlockReward = \"block_reward\"\n\t// IncorrectBlocksPerDay is value of incorrect blocks per day before global ban\n\tIncorrectBlocksPerDay = `incorrect_blocks_per_day`\n\t// NodeBanTime is value of ban time for bad nodes (in ms)\n\tNodeBanTime = `node_ban_time`\n\t// LocalNodeBanTime is value of local ban time for bad nodes (in ms)\n\tLocalNodeBanTime = `local_node_ban_time`\n\t// TaxesSize is the value of the taxes\n\tTaxesSize = `taxes_size`\n\t// PriceTxSize is the size of a user's resource in the database\n\tPriceTxSize = `price_tx_size`\n\t// PriceCreateRate is new element rate, include table,contract,column,ecosystem,page,menu\n\tPriceCreateRate = `price_create_rate`\n\t// Test equals true or 1 if we have a test blockchain\n\tTest = `test`\n\t// PrivateBlockchain is value defining blockchain mode\n\tPrivateBlockchain = `private_blockchain`\n\n\t// CostDefault is the default maximum cost of F\n\tCostDefault = int64(20000000)\n\n\tPriceExec       = \"price_exec_\"\n\tAccessExec      = \"access_exec_\"\n\tPriceCreateExec = \"price_create_exec_\"\n\tPayFreeContract = \"pay_free_contract\"\n)\n\nvar (\n\tcache               = map[string]string{}\n\tnodes               = make(map[string]*HonorNode)\n\tnodesByPosition     = make([]*HonorNode, 0)\n\tfuels               = make(map[int64]string)\n\twallets             = make(map[int64]string)\n\tmutex               = &sync.RWMutex{}\n\tfirstBlockData      *types.FirstBlock\n\tfirstBlockTimestamp int64\n\terrFirstBlockData   = errors.New(\"failed to get data of the first block\")\n\terrNodeDisabled     = errors.New(\"node is disabled\")\n\tnodePubKey          []byte\n\tnodePrivKey         []byte\n\tcacheTableColType   = make([]map[string]string, 0)\n\trunModel            uint8\n)\n\nfunc ReadNodeKeys() (err error) {\n\tvar (\n\t\tnprivkey []byte\n\t)\n\tnprivkey, err = os.ReadFile(filepath.Join(conf.Config.DirPathConf.KeysDir, consts.NodePrivateKeyFilename))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading node private key from file\")\n\t\treturn\n\t}\n\tnodePrivKey, err = hex.DecodeString(string(nprivkey))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"decoding node private key from hex\")\n\t\treturn\n\t}\n\tnodePubKey, err = crypto.PrivateToPublic(nodePrivKey)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"converting node private key to public\")\n\t\treturn\n\t}\n\treturn\n}\n\nfunc GetSysParCache() map[string]string {\n\tvar cp = make(map[string]string, len(cache))\n\tfor k, v := range cache {\n\t\tcp[k] = v\n\t}\n\treturn cp\n}\n\nfunc GetNodePubKey() []byte {\n\treturn nodePubKey\n}\n\nfunc GetNodePrivKey() []byte {\n\treturn nodePrivKey\n}\n\n// SysUpdate reloads/updates values of platform parameters\nfunc SysUpdate(dbTx *sqldb.DbTransaction) error {\n\tvar err error\n\tplatformParameters, err := sqldb.GetAllPlatformParameters(dbTx, nil, nil, nil)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all platform parameters\")\n\t\treturn err\n\t}\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\tfor _, param := range platformParameters {\n\t\tcache[param.Name] = param.Value\n\t}\n\tif len(cache[HonorNodes]) > 0 {\n\t\tif err = updateNodes(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tgetParams := func(name string) (map[int64]string, error) {\n\t\tres := make(map[int64]string)\n\t\tif len(cache[name]) > 0 {\n\t\t\tifuels := make([][]string, 0)\n\t\t\terr = json.Unmarshal([]byte(cache[name]), &ifuels)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling params from json\")\n\t\t\t\treturn res, err\n\t\t\t}\n\t\t\tfor _, item := range ifuels {\n\t\t\t\tif len(item) < 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tres[converter.StrToInt64(item[0])] = item[1]\n\t\t\t}\n\t\t}\n\t\treturn res, nil\n\t}\n\tfuels, err = getParams(FuelRate)\n\twallets, err = getParams(TaxesWallet)\n\n\treturn err\n}\n\nfunc updateNodes() (err error) {\n\titems := make([]*HonorNode, 0)\n\tif len(cache[HonorNodes]) > 0 {\n\t\terr = json.Unmarshal([]byte(cache[HonorNodes]), &items)\n\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err, \"v\": cache[HonorNodes]}).Error(\"unmarshalling honor nodes from json\")\n\t\t\treturn err\n\t\t}\n\t}\n\tif len(items) > 1 {\n\t\tif err = DuplicateHonorNode(items); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tnodes = make(map[string]*HonorNode)\n\tnodesByPosition = []*HonorNode{}\n\tfor i := 0; i < len(items); i++ {\n\t\tnodes[hex.EncodeToString(items[i].PublicKey)] = items[i]\n\n\t\tif !items[i].Stopped {\n\t\t\tnodesByPosition = append(nodesByPosition, items[i])\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// addHonorNodeKeys adds node by keys to list of nodes\nfunc addHonorNodeKeys(publicKey []byte) {\n\tnodesByPosition = append(nodesByPosition, &HonorNode{\n\t\tPublicKey: publicKey,\n\t})\n}\n\nfunc GetNodes() []HonorNode {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\n\tresult := make([]HonorNode, 0, len(nodesByPosition))\n\tfor _, node := range nodesByPosition {\n\t\tresult = append(result, *node)\n\t}\n\n\treturn result\n}\n\nfunc GetThisNodePosition() (int64, error) {\n\treturn GetNodePositionByPublicKey(GetNodePubKey())\n}\n\nfunc GetHonorNodeType() bool {\n\td, err := GetNodePositionByPublicKey(GetNodePubKey())\n\tif err == nil {\n\t\treturn true\n\t}\n\tif d == 0 && err != nil {\n\t\treturn false\n\t}\n\treturn false\n}\n\n// GetNodePositionByPublicKey is returning node position by key id\nfunc GetNodePositionByPublicKey(publicKey []byte) (int64, error) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\n\tfor i, item := range nodesByPosition {\n\t\tif item.Stopped {\n\t\t\tif bytes.Equal(item.PublicKey, publicKey) {\n\t\t\t\treturn 0, errNodeDisabled\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif bytes.Equal(item.PublicKey, publicKey) {\n\t\t\treturn int64(i), nil\n\t\t}\n\t}\n\n\treturn 0, fmt.Errorf(\"incorrect public key\")\n}\n\n// GetCountOfActiveNodes is count of nodes with stopped = false\nfunc GetCountOfActiveNodes() int64 {\n\treturn int64(len(nodesByPosition))\n}\n\n// GetNumberOfNodes is count number of nodes\nfunc GetNumberOfNodes() int64 {\n\treturn int64(len(nodesByPosition))\n}\n\nfunc GetNumberOfNodesFromDB(transaction *sqldb.DbTransaction) int64 {\n\tvar bk sqldb.BlockChain\n\tf, err := bk.GetMaxBlock()\n\tif err != nil || !f {\n\t\treturn 1\n\t}\n\tif bk.ConsensusMode == consts.CandidateNodeMode {\n\t\tvar candidate sqldb.CandidateNode\n\t\tvar total int64\n\t\tpledgeAmount, err := sqldb.GetPledgeAmount()\n\t\tif err != nil {\n\t\t\treturn 1\n\t\t}\n\t\terr = sqldb.GetDB(transaction).Table(candidate.TableName()).Where(\"deleted = 0 AND earnest_total >= ?\", pledgeAmount).Limit(SysInt(NumberNodes)).Count(&total).Error\n\t\tif err != nil {\n\t\t\treturn 1\n\t\t}\n\t\tif total < 1 {\n\t\t\ttotal = 1\n\t\t}\n\t\treturn total\n\t}\n\tsp := &sqldb.PlatformParameter{}\n\tsp.GetTransaction(transaction, HonorNodes)\n\tvar honorNodes []map[string]any\n\tif len(sp.Value) > 0 {\n\t\tif err := json.Unmarshal([]byte(sp.Value), &honorNodes); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err, \"value\": sp.Value}).Error(\"unmarshalling honor nodes from JSON\")\n\t\t}\n\t}\n\tif len(honorNodes) == 0 {\n\t\treturn 1\n\t}\n\treturn int64(len(honorNodes))\n}\n\n// GetNodeByPosition is retrieving node by position\nfunc GetNodeByPosition(position int64) (*HonorNode, error) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif int64(len(nodesByPosition)) <= position {\n\t\treturn nil, fmt.Errorf(\"incorrect position\")\n\t}\n\treturn nodesByPosition[position], nil\n}\n\nfunc GetNodeByHost(host string) (HonorNode, error) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tfor _, n := range nodes {\n\t\tif n.TCPAddress == host {\n\t\t\treturn *n, nil\n\t\t}\n\t}\n\n\treturn HonorNode{}, fmt.Errorf(\"incorrect host\")\n}\n\n// GetNodeHostByPosition is retrieving node host by position\nfunc GetNodeHostByPosition(position int64) (string, error) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif IsCandidateNodeMode() {\n\t\tcandidateNode := &sqldb.CandidateNode{}\n\t\terr := candidateNode.GetCandidateNodeById(position)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tnodePublicKey, err := hex.DecodeString(candidateNode.NodePubKey)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tnodePublicKey = crypto.CutPub(nodePublicKey)\n\n\t\treturn candidateNode.TcpAddress, nil\n\t}\n\n\tnodeData, err := GetNodeByPosition(position)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn nodeData.TCPAddress, nil\n}\n\n// GetNodePublicKeyByPosition is retrieving node public key by position\nfunc GetNodePublicKeyByPosition(position int64) ([]byte, error) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif IsCandidateNodeMode() {\n\t\tcandidateNode := &sqldb.CandidateNode{}\n\t\terr := candidateNode.GetCandidateNodeById(position)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnodePublicKey, err := hex.DecodeString(candidateNode.NodePubKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnodePublicKey = crypto.CutPub(nodePublicKey)\n\n\t\treturn nodePublicKey, nil\n\t}\n\tif int64(len(nodesByPosition)) <= position {\n\t\treturn nil, fmt.Errorf(\"incorrect position\")\n\t}\n\tnodeData, err := GetNodeByPosition(position)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn nodeData.PublicKey, nil\n}\n\n// SysInt64 is converting sys string to int64\nfunc SysInt64(name string) int64 {\n\treturn converter.StrToInt64(SysString(name))\n}\n\n// SysInt is converting sys string to int\nfunc SysInt(name string) int {\n\treturn converter.StrToInt(SysString(name))\n}\n\n// GetSizeFuel is returns fuel size\nfunc GetSizeFuel() int64 {\n\treturn SysInt64(SizeFuel)\n}\n\n// GetFuelRate is returning fuel rate\nfunc GetFuelRate(ecosystem int64) string {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif ret, ok := fuels[ecosystem]; ok {\n\t\treturn ret\n\t}\n\treturn ``\n}\n\n// HasFuelRate is returns fuels exist\nfunc HasFuelRate(ecosystem int64) (string, bool) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif ret, ok := fuels[ecosystem]; ok {\n\t\treturn ret, ok\n\t}\n\treturn \"\", false\n}\n\n// GetTaxesWallet is returns taxes wallet\nfunc GetTaxesWallet(ecosystem int64) string {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif ret, ok := wallets[ecosystem]; ok {\n\t\treturn ret\n\t}\n\treturn ``\n}\n\n// HasTaxesWallet is returns taxes exist\nfunc HasTaxesWallet(ecosystem int64) (string, bool) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif ret, ok := wallets[ecosystem]; ok {\n\t\treturn ret, ok\n\t}\n\treturn \"\", false\n}\n\n// GetMaxBlockSize is returns max block size\nfunc GetMaxBlockSize() int64 {\n\treturn converter.StrToInt64(SysString(MaxBlockSize))\n}\n\n// GetMaxBlockFuel is returns max block fuel\nfunc GetMaxBlockFuel() int64 {\n\treturn converter.StrToInt64(SysString(MaxBlockFuel))\n}\n\n// GetMaxTxFuel is returns max tx fuel\nfunc GetMaxTxFuel() int64 {\n\treturn converter.StrToInt64(SysString(MaxTxFuel))\n}\n\n// GetMaxBlockGenerationTime is returns max block generation time (in ms)\nfunc GetMaxBlockGenerationTime() int64 {\n\treturn converter.StrToInt64(SysString(MaxBlockGenerationTime))\n}\n\n// GetGapsBetweenBlocks is returns gaps between blocks\nfunc GetGapsBetweenBlocks() int64 {\n\treturn converter.StrToInt64(SysString(GapsBetweenBlocks))\n}\n\n// GetMaxBlockTimeDuration return max block time duration\nfunc GetMaxBlockTimeDuration() time.Duration {\n\treturn time.Millisecond*time.Duration(GetMaxBlockGenerationTime()) + time.Second*time.Duration(GetGapsBetweenBlocks())\n}\n\n// GetMaxTxSize is returns max tx size\nfunc GetMaxTxSize() int64 {\n\treturn converter.StrToInt64(SysString(MaxTxSize))\n}\n\n// GetMaxTxTextSize is returns max tx text size\nfunc GetMaxForsignSize() int64 {\n\treturn converter.StrToInt64(SysString(MaxForsignSize))\n}\n\n// GetMaxTxCount is returns max tx count\nfunc GetMaxTxCount() int {\n\treturn converter.StrToInt(SysString(MaxTxCount))\n}\n\n// GetMaxColumns is returns max columns\nfunc GetMaxColumns() int {\n\treturn converter.StrToInt(SysString(MaxColumns))\n}\n\n// GetMaxIndexes is returns max indexes\nfunc GetMaxIndexes() int {\n\treturn converter.StrToInt(SysString(MaxIndexes))\n}\n\n// GetMaxBlockUserTx is returns max tx block user\nfunc GetMaxBlockUserTx() int {\n\treturn converter.StrToInt(SysString(MaxBlockUserTx))\n}\n\nfunc IsTestMode() bool {\n\treturn SysString(Test) == `true` || SysString(Test) == `1`\n}\n\nfunc GetIncorrectBlocksPerDay() int {\n\treturn converter.StrToInt(SysString(IncorrectBlocksPerDay))\n}\n\nfunc GetNodeBanTime() time.Duration {\n\treturn time.Millisecond * time.Duration(converter.StrToInt64(SysString(NodeBanTime)))\n}\n\nfunc GetLocalNodeBanTime() time.Duration {\n\treturn time.Millisecond * time.Duration(converter.StrToInt64(SysString(LocalNodeBanTime)))\n}\n\n// GetDefaultRemoteHosts returns array of hostnames excluding myself\nfunc GetDefaultRemoteHosts() []string {\n\tret := make([]string, 0)\n\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\n\tnodeKey := hex.EncodeToString(GetNodePubKey())\n\tfor pubKey, item := range nodes {\n\t\tif pubKey != nodeKey && !item.Stopped {\n\t\t\tret = append(ret, item.TCPAddress)\n\t\t}\n\t}\n\tif len(ret) == 0 && len(conf.Config.BootNodes.NodesAddr) > 0 {\n\t\tret = append(ret, conf.Config.BootNodes.NodesAddr[0])\n\t}\n\treturn ret\n}\n\n// GetRemoteHosts returns array of hostnames excluding myself\nfunc GetRemoteHosts() []string {\n\tret := make([]string, 0)\n\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\n\tnodeKey := hex.EncodeToString(GetNodePubKey())\n\tfor pubKey, item := range nodes {\n\t\tif pubKey != nodeKey && !item.Stopped {\n\t\t\tret = append(ret, item.TCPAddress)\n\t\t}\n\t}\n\treturn ret\n}\n\n// SysString returns string value of the system parameter\nfunc SysString(name string) string {\n\tmutex.RLock()\n\tret := cache[name]\n\tmutex.RUnlock()\n\treturn ret\n}\n\n// GetRbBlocks1 is returns RbBlocks1\nfunc GetRbBlocks1() int64 {\n\treturn SysInt64(RbBlocks1)\n}\n\n// HasSys returns boolean whether this system parameter exists\nfunc HasSys(name string) bool {\n\tmutex.RLock()\n\t_, ok := cache[name]\n\tmutex.RUnlock()\n\treturn ok\n}\n\nfunc SetFirstBlockTimestamp(data int64) {\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\tfirstBlockTimestamp = data\n}\n\n// SetFirstBlockData sets data of first block to global variable\nfunc SetFirstBlockData(data *types.FirstBlock) {\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\n\tfirstBlockData = data\n\n\t// If list of nodes is empty, then used node from the first block\n\tif len(nodesByPosition) == 0 {\n\t\taddHonorNodeKeys(firstBlockData.NodePublicKey)\n\n\t\tnodesByPosition = []*HonorNode{{\n\t\t\tPublicKey: firstBlockData.NodePublicKey,\n\t\t\tStopped:   false,\n\t\t}}\n\t}\n}\n\nfunc GetFirstBlockTimestamp() int64 {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\n\treturn firstBlockTimestamp\n}\n\n// GetFirstBlockData gets data of first block from global variable\nfunc GetFirstBlockData() (*types.FirstBlock, error) {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\n\tif firstBlockData == nil {\n\t\treturn nil, errFirstBlockData\n\t}\n\n\treturn firstBlockData, nil\n}\n\n// IsPrivateBlockchain returns the value of private_blockchain system parameter or true\nfunc IsPrivateBlockchain() bool {\n\tpar := SysString(PrivateBlockchain)\n\treturn len(par) > 0 && par != `0` && par != `false`\n}\n\nfunc GetMaxCost() int64 {\n\tcost := GetMaxTxFuel()\n\tif cost == 0 {\n\t\tcost = CostDefault\n\t}\n\treturn cost\n}\n\nfunc GetAccessExec(s string) string {\n\treturn SysString(AccessExec + s)\n}\n\nfunc GetPriceExec(s string) (price int64, ok bool) {\n\tif ok = HasSys(PriceExec + s); !ok {\n\t\treturn\n\t}\n\tprice = SysInt64(PriceExec + s)\n\treturn\n}\n\nfunc GetPriceCreateExec(s string) (price int64) {\n\tif ok := HasSys(PriceCreateExec + s); !ok {\n\t\treturn\n\t}\n\tprice = SysInt64(PriceCreateExec + s)\n\treturn\n}\n\n// SysTableColType reloads/updates values of all ecosystem table column data type\nfunc SysTableColType(dbTx *sqldb.DbTransaction) error {\n\tvar err error\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tcacheTableColType, err = dbTx.GetAllTransaction(`\n\t\tSELECT table_name,column_name,data_type,character_maximum_length\n\t\tFROM information_schema.columns Where table_schema NOT IN ('pg_catalog', 'information_schema') AND table_name ~ '[\\d]' AND data_type = 'bytea' ORDER BY ordinal_position ASC;`, -1)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc GetTableColType() []map[string]string {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\treturn cacheTableColType\n}\n\nfunc IsByteColumn(table, column string) bool {\n\tfor _, row := range GetTableColType() {\n\t\tif row[\"table_name\"] == table && row[\"column_name\"] == column {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc SetRunModel(setVal uint8) {\n\trunModel = setVal\n}\n\nfunc IsHonorNodeMode() bool {\n\treturn runModel == consts.HonorNodeMode\n}\n\nfunc IsCandidateNodeMode() bool {\n\treturn runModel == consts.CandidateNodeMode\n}\n"
  },
  {
    "path": "packages/conf/types.go",
    "content": "package conf\n\ntype (\n\t// HostPort endpoint in form \"str:int\"\n\tHostPort struct {\n\t\tHost string // ipaddr, hostname, or \"0.0.0.0\"\n\t\tPort int    // must be in range 1..65535\n\t}\n\n\t// DBConfig database connection parameters\n\tDBConfig struct {\n\t\tName            string\n\t\tHost            string\n\t\tPort            int\n\t\tUser            string\n\t\tPassword        string\n\t\tLockTimeout     int // lock_timeout in milliseconds\n\t\tIdleInTxTimeout int // postgres parameter idle_in_transaction_session_timeout\n\t\tMaxIdleConns    int // sets the maximum number of connections in the idle connection pool\n\t\tMaxOpenConns    int // sets the maximum number of open connections to the database\n\t}\n\n\t//RedisConfig get redis information from config.yml\n\tRedisConfig struct {\n\t\tEnable   bool\n\t\tHost     string\n\t\tPort     int\n\t\tPassword string\n\t\tDbName   int\n\t}\n\n\t// StatsDConfig statd connection parameters\n\tStatsDConfig struct {\n\t\tHost string\n\t\tPort int\n\t\tName string\n\t}\n\n\t// CentrifugoConfig connection params\n\tCentrifugoConfig struct {\n\t\tSecret string\n\t\tURL    string\n\t\tKey    string\n\t}\n\n\t// Syslog represents parameters of syslog\n\tSyslog struct {\n\t\tFacility string\n\t\tTag      string\n\t}\n\n\t// LogConfig represents parameters of log\n\tLogConfig struct {\n\t\tLogTo     string\n\t\tLogLevel  string\n\t\tLogFormat string\n\t\tSyslog    Syslog\n\t}\n\n\t// TokenMovementConfig smtp config for token movement\n\tTokenMovementConfig struct {\n\t\tHost     string\n\t\tPort     int\n\t\tUsername string\n\t\tPassword string\n\t\tTo       string\n\t\tFrom     string\n\t\tSubject  string\n\t}\n\n\t// BanKeyConfig parameters\n\tBanKeyConfig struct {\n\t\tBadTime int // control time period in minutes\n\t\tBanTime int // ban time in minutes\n\t\tBadTx   int // maximum bad tx during badTime minutes\n\t}\n\n\tTLSConfig struct {\n\t\tEnabled bool   // TLS is on/off. It is required for https\n\t\tTLSCert string // TLSCert is a filepath of the fullchain of certificate.\n\t\tTLSKey  string // TLSKey is a filepath of the private key.\n\t}\n\n\tDirectoryConfig struct {\n\t\tDataDir        string // application work dir (cwd by default)\n\t\tPidFilePath    string\n\t\tLockFilePath   string\n\t\tTempDir        string // temporary dir\n\t\tKeysDir        string // place for private keys files: NodePrivateKey, PrivateKey\n\t\tFirstBlockPath string\n\t}\n\n\tBootstrapNodeConfig struct {\n\t\tNodesAddr []string\n\t}\n\n\tCryptoSettings struct {\n\t\tCryptoer string\n\t\tHasher   string\n\t}\n\n\t//LocalConfig TODO: uncategorized\n\tLocalConfig struct {\n\t\tRunNodeMode           string\n\t\tHTTPServerMaxBodySize int64\n\t\tNetworkID             int64\n\t\tMaxPageGenerationTime int64 // in milliseconds\n\t}\n\tBlockSyncMethod struct {\n\t\tMethod string\n\t}\n\t// GlobalConfig is storing all startup config as global struct\n\tGlobalConfig struct {\n\t\tKeyID        int64  `toml:\"-\"`\n\t\tConfigPath   string `toml:\"-\"`\n\t\tTestRollBack bool   `toml:\"-\"`\n\t\tFuncBench    bool   `toml:\"-\"`\n\t\tLocalConf    LocalConfig\n\t\tDirPathConf  DirectoryConfig\n\t\tBootNodes    BootstrapNodeConfig\n\t\tTLSConf      TLSConfig\n\t\tTCPServer    HostPort\n\t\tHTTP         HostPort\n\t\tJsonRPC      struct {\n\t\t\tEnabled   bool\n\t\t\tNamespace string\n\t\t}\n\t\tDB              DBConfig\n\t\tRedis           RedisConfig\n\t\tStatsD          StatsDConfig\n\t\tCentrifugo      CentrifugoConfig\n\t\tLog             LogConfig\n\t\tTokenMovement   TokenMovementConfig\n\t\tBanKey          BanKeyConfig\n\t\tCryptoSettings  CryptoSettings\n\t\tBlockSyncMethod BlockSyncMethod\n\t}\n)\n"
  },
  {
    "path": "packages/consts/conf.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage consts\n\nconst (\n\t// DefaultConfigFile name of config file (toml format)\n\tDefaultConfigFile = \"config.toml\"\n\n\t// DefaultTempDirName is default name of temporary directory\n\tDefaultTempDirName = \"ibax-temp\"\n\n\t// DefaultWorkdirName name of working directory\n\tDefaultWorkdirName = \"data\"\n\n\t// DefaultPidFilename is default filename of pid file\n\tDefaultPidFilename = \"go-ibax.pid\"\n\n\t// DefaultLockFilename is default filename of lock file\n\tDefaultLockFilename = \"go-ibax.lock\"\n\n\t// FirstBlockFilename name of first block binary file\n\tFirstBlockFilename = \"1block\"\n\n\t// PrivateKeyFilename name of wallet private key file\n\tPrivateKeyFilename = \"PrivateKey\"\n\n\t// PublicKeyFilename name of wallet public key file\n\tPublicKeyFilename = \"PublicKey\"\n\n\t// NodePrivateKeyFilename name of node private key file\n\tNodePrivateKeyFilename = \"NodePrivateKey\"\n\n\t// NodePublicKeyFilename name of node public key file\n\tNodePublicKeyFilename = \"NodePublicKey\"\n\n\t// KeyIDFilename generated KeyID\n\tKeyIDFilename = \"KeyID\"\n)\n"
  },
  {
    "path": "packages/consts/consts.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage consts\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n)\n\n// VERSION is current version\nconst VERSION = \"1.4.3\"\n\nconst BvRollbackHash = 2\nconst BvIncludeRollbackHash = 3\n\n// BlockVersion is block version\nconst BlockVersion = BvIncludeRollbackHash\n\n// DefaultTcpPort used when port number missed in host addr\nconst DefaultTcpPort = 7078\n\n// FounderAmount is the starting amount of founder\nconst FounderAmount = 5250000\n\n// MoneyDigits is numbers of digits for tokens 1000000000000\nconst MoneyDigits = 12\n\n// WaitConfirmedNodes is used in confirmations\nconst WaitConfirmedNodes = 10\n\n// MinConfirmedNodes The number of nodes which should have the same block as we have for regarding this block belongs to the major part of DC-net. For get_confirmed_block_id()\nconst MinConfirmedNodes = 0\n\n// MaxTxForw How fast could the time of transaction pass\nconst MaxTxForw = 600\n\n// MaxTxBack transaction may wander in the net for a day and then get into a block\nconst MaxTxBack = 86400\n\n// RoundFix is rounding constant\nconst RoundFix = 0.00000000001\n\n// ReadTimeout is timeout for TCP\nconst ReadTimeout = 20\n\n// WriteTimeout is timeout for TCP\nconst WriteTimeout = 20\n\n// AddressLength is length of address\nconst AddressLength = 20\n\n// PubkeySizeLength is pubkey length\nconst PubkeySizeLength = 64\n\n// PrivkeyLength is privkey length\nconst PrivkeyLength = 32\n\n// BlockSize is size of block\nconst BlockSize = 16\n\n// HashSize is size of hash\nconst HashSize = 32\n\nconst AvailableBCGap = 4\n\nconst DefaultNodesConnectDelay = 6\n\nconst MaxTXAttempt = 10\n\n// ChainSize 1M = 1048576 byte\nconst ChainSize = 1 << 20\n\n// DefaultTokenSymbol define default token symbol\nconst DefaultTokenSymbol = \"IBXC\"\n\n// DefaultTokenName define default token name\nconst DefaultTokenName = \"IBAX Coin\"\n\n// DefaultEcosystemName define default ecosystem name\nconst DefaultEcosystemName = \"platform ecosystem\"\n\n// ApiPath is the beginning of the api url\nvar ApiPath = `/api/v2/`\n\n// BuildInfo should be defined through -ldflags\nvar BuildInfo string\n\nconst (\n\t// RollbackResultFilename rollback result file\n\tRollbackResultFilename = \"rollback_result\"\n\n\t// FromToPerDayLimit day limit token transfer between accounts\n\tFromToPerDayLimit = 10000\n\n\t// TokenMovementQtyPerBlockLimit block limit token transfer\n\tTokenMovementQtyPerBlockLimit = 100\n\n\t// TCPConnTimeout timeout of tcp connection\n\tTCPConnTimeout = 5 * time.Second\n\n\t// TxRequestExpire is expiration time for request of transaction\n\tTxRequestExpire = 1 * time.Minute\n\n\t// DefaultCLB always is 1\n\tDefaultCLB = 1\n\n\t// MoneyLength is the maximum number of digits in money value\n\tMoneyLength = 30\n\n\tDefaultTokenEcosystem = 1\n\n\t// ShiftContractID is the offset of tx identifiers\n\tShiftContractID = 5000\n\n\t// ContractList is the number of contracts per page on loading\n\tContractList = 200\n\n\t// Guest key\n\tGuestPublic  = \"ef0ab117793962b7b3ee8d2ae94b58bbd7db1aa856a7dc623fdb28ad530090b0bcf5cb81b4d6912a249f1ab30921f414ad88383208cd8ba26ae2a9c3eb543772\"\n\tGuestKey     = \"-110277540701013350\"\n\tGuestAddress = \"1833-6466-5330-0853-8266\"\n\n\t// StatusMainPage is a status for Main Page\n\tStatusMainPage = `2`\n\n\tNoneCLB     = \"none\"\n\tDBFindLimit = 10000\n\n\tHonorNodeMode     = 1\n\tCandidateNodeMode = 2\n)\n\nconst (\n\tSavePointMarkBlock = \"block\"\n\tSavePointMarkTx    = \"tx\"\n)\n\nfunc Version() string {\n\treturn strings.TrimSpace(strings.Join([]string{VERSION, BuildInfo}, \" \"))\n}\n\nfunc SetSavePointMarkBlock(idTx string) string {\n\treturn fmt.Sprintf(\"\\\"%s-%s\\\";\", SavePointMarkBlock, idTx)\n}\n\nconst (\n\tUTXO_Type_First_Block  = 1 //Initialize the first block\n\tUTXO_Type_Self_UTXO    = 11\n\tUTXO_Type_Self_Account = 12\n\tUTXO_Type_Packaging    = 20\n\tUTXO_Type_Taxes        = 21\n\tUTXO_Type_Output       = 22\n\tUTXO_Type_Combustion   = 23\n\tUTXO_Type_Transfer     = 26\n)\n"
  },
  {
    "path": "packages/consts/log_types.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage consts\n\n// LogEventType is storing numeric event type\ntype LogEventType int\n\n// Types of log errors\nconst (\n\tNetworkError             = \"Network\"\n\tJSONMarshallError        = \"JSONMarshall\"\n\tJSONUnmarshallError      = \"JSONUnmarshall\"\n\tCommandExecutionError    = \"CommandExecution\"\n\tConversionError          = \"Conversion\"\n\tTypeError                = \"Type\"\n\tProtocolError            = \"Protocol\"\n\tMarshallingError         = \"Marshall\"\n\tUnmarshallingError       = \"Unmarshall\"\n\tParseError               = \"Parse\"\n\tIOError                  = \"IO\"\n\tCryptoError              = \"Crypto\"\n\tContractError            = \"Contract\"\n\tDBError                  = \"DB\"\n\tPanicRecoveredError      = \"Panic\"\n\tConnectionError          = \"Connection\"\n\tConfigError              = \"Config\"\n\tVMError                  = \"VM\"\n\tJustWaiting              = \"JustWaiting\"\n\tNtpdate                  = \"Ntpdate\"\n\tBlockError               = \"Block\"\n\tParserError              = \"Parser\"\n\tContextError             = \"Context\"\n\tSessionError             = \"Session\"\n\tRouteError               = \"Route\"\n\tNotFound                 = \"NotFound\"\n\tFound                    = \"Found\"\n\tEmptyObject              = \"EmptyObject\"\n\tInvalidObject            = \"InvalidObject\"\n\tDuplicateObject          = \"DuplicateObject\"\n\tUnknownObject            = \"UnknownObject\"\n\tParameterExceeded        = \"ParameterExceeded\"\n\tDivisionByZero           = \"DivisionByZero\"\n\tEvalError                = \"Eval\"\n\tJWTError                 = \"JWT\"\n\tAccessDenied             = \"AccessDenied\"\n\tSizeDoesNotMatch         = \"SizeDoesNotMatch\"\n\tNoIndex                  = \"NoIndex\"\n\tNoFunds                  = \"NoFunds\"\n\tBlockIsFirst             = \"BlockIsFirst\"\n\tIncorrectCallingContract = \"IncorrectCallingContract\"\n\tWritingFile              = \"WritingFile\"\n\tCentrifugoError          = \"CentrifugoError\"\n\tStatsdError              = \"StatsdError\"\n\tMigrationError           = \"MigrationError\"\n\tAutoupdateError          = \"AutoupdateError\"\n\tBCRelevanceError         = \"BCRelevanceError\"\n\tBCActualizationError     = \"BCActualizationError\"\n\tSchedulerError           = \"SchedulerError\"\n\tSyncProcess              = \"SyncProcess\"\n\tWrongModeError           = \"WrongModeError\"\n\tCLBManagerError          = \"CLBManagerError\"\n\tTCPClientError           = \"TCPClientError\"\n\tBadTxError               = \"BadTxError\"\n\tTimeCalcError            = \"BlockTimeCounterError\"\n\tRegisterError            = \"RegisterError\"\n\tJsonRpcError             = \"JsonRpcError\"\n)\n"
  },
  {
    "path": "packages/consts/used_stop_certs.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage consts\n\n// UsedStopNetworkCerts contains a list of certificates that were used to stop the network\nvar UsedStopNetworkCerts = [][]byte{}\n"
  },
  {
    "path": "packages/converter/address.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage converter\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n)\n\ntype Hole struct {\n\tK int64\n\tS string\n}\n\nconst (\n\tBlackHoleAddr = \"BlackHole\"\n\tWhiteHoleAddr = \"WhiteHole\"\n)\n\nvar (\n\tHoleAddrMap = map[string]Hole{\n\t\tBlackHoleAddr: {K: 0, S: \"0000-0000-0000-0000-0000\"},\n\t\tWhiteHoleAddr: {K: 5555, S: \"0000-0000-0000-0000-5555\"},\n\t}\n)\n\n// AddressToID converts the string representation of the wallet number to a numeric\nfunc AddressToID(input string) (addr int64) {\n\tinput = strings.TrimSpace(input)\n\tif len(input) < 2 {\n\t\treturn 0\n\t}\n\tif input[0] == '-' {\n\t\tuaddr, err := strconv.ParseInt(input, 10, 64)\n\t\tif err != nil {\n\n\t\t}\n\t\taddr = uaddr\n\t} else if has4LineContain(input) {\n\t\taddr = StringToAddress(input)\n\t} else {\n\t\tuaddr, err := strconv.ParseUint(input, 10, 64)\n\t\tif err != nil {\n\n\t\t}\n\t\taddr = int64(uaddr)\n\t}\n\tif IDToAddress(addr) == `invalid` {\n\t\treturn 0\n\t}\n\treturn\n}\n\n// IDToAddress converts the identifier of account to a string of the form xxxx-xxxx-xxxx-xxxx-xxxx.\nfunc IDToAddress(id int64) (out string) {\n\tout = AddressToString(id)\n\tif !IsValidAddress(out) {\n\t\tout = `invalid`\n\t}\n\treturn\n}\n\n// AddressToString converts int64 address to chain address as xxxx-xxxx-xxxx-xxxx-xxxx.\nfunc AddressToString(int int64) (str string) {\n\treturn AddressToStringUint64(uint64(int))\n}\n\nfunc AddressToStringUint64(uint uint64) (str string) {\n\tnum := strconv.FormatUint(uint, 10)\n\tval := []byte(strings.Repeat(\"0\", consts.AddressLength-len(num)) + num)\n\tfor i := 0; i <= 4; i++ {\n\t\tif i == 4 {\n\t\t\tstr += string(val[i*4:])\n\t\t\tbreak\n\t\t}\n\t\tstr += string(val[i*4:(i+1)*4]) + `-`\n\t}\n\treturn\n}\n\n// StringToAddress converts string chain address to int64 address. The input address can be a positive or negative\n// number, or chain address in xxxx-xxxx-xxxx-xxxx-xxxx format. Returns 0 when error occurs.\nfunc StringToAddress(str string) (result int64) {\n\tvar (\n\t\terr error\n\t\tret uint64\n\t)\n\tif len(str) == 0 {\n\t\treturn 0\n\t}\n\t//string of int64\n\tif str[0] == '-' {\n\t\tvar id int64\n\t\tid, err = strconv.ParseInt(str, 10, 64)\n\t\tif err != nil {\n\t\t\treturn 0\n\t\t}\n\t\tstr = strconv.FormatUint(uint64(id), 10)\n\t}\n\tif len(str) < consts.AddressLength {\n\t\tstr = strings.Repeat(`0`, consts.AddressLength-len(str)) + str\n\t}\n\tval := []byte(strings.Replace(str, `-`, ``, -1))\n\tif len(val) != consts.AddressLength {\n\t\treturn 0\n\t}\n\tif ret, err = strconv.ParseUint(string(val), 10, 64); err != nil {\n\t\treturn 0\n\t}\n\tif CheckSum(val[:len(val)-1]) != int(val[len(val)-1]-'0') {\n\t\treturn 0\n\t}\n\tresult = int64(ret)\n\treturn\n}\n\n// IsValidAddress checks if the specified address is chain address.\nfunc IsValidAddress(address string) bool {\n\tval := []byte(strings.Replace(address, `-`, ``, -1))\n\tif len(val) != consts.AddressLength {\n\t\treturn false\n\t}\n\tif _, err := strconv.ParseUint(string(val), 10, 64); err != nil {\n\t\treturn false\n\t}\n\treturn CheckSum(val[:len(val)-1]) == int(val[len(val)-1]-'0')\n}\n\n// CheckSum calculates the 0-9 check sum of []byte\nfunc CheckSum(val []byte) int {\n\tvar one, two int\n\tfor i, ch := range val {\n\t\tdigit := int(ch - '0')\n\t\tif i&1 == 1 {\n\t\t\tone += digit\n\t\t} else {\n\t\t\ttwo += digit\n\t\t}\n\t}\n\tchecksum := (two + 3*one) % 10\n\tif checksum > 0 {\n\t\tchecksum = 10 - checksum\n\t}\n\treturn checksum\n}\n\nfunc has4LineContain(str string) bool {\n\treturn strings.Count(str, \"-\") == 4\n}\n"
  },
  {
    "path": "packages/converter/converter.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage converter\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar ErrSliceSize = errors.New(\"Slice size larger than buffer size\")\n\nvar FirstEcosystemTables = map[string]bool{\n\t`keys`:               true,\n\t`menu`:               true,\n\t`pages`:              true,\n\t`snippets`:           true,\n\t`languages`:          true,\n\t`contracts`:          true,\n\t`tables`:             true,\n\t`parameters`:         true,\n\t`history`:            true,\n\t`sections`:           true,\n\t`members`:            true,\n\t`roles`:              true,\n\t`roles_participants`: true,\n\t`notifications`:      true,\n\t`applications`:       true,\n\t`binaries`:           true,\n\t`buffer_data`:        true,\n\t`app_params`:         true,\n\t`views`:              true,\n}\n\nfunc EncodeLenInt64(data *[]byte, x int64) *[]byte {\n\tvar length int\n\tbuf := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(buf, uint64(x))\n\tfor length = 8; length > 0 && buf[length-1] == 0; length-- {\n\t}\n\t*data = append(append(*data, byte(length)), buf[:length]...)\n\treturn data\n}\n\nfunc EncodeLenInt64InPlace(x int64) []byte {\n\tbuf := make([]byte, 9)\n\tvalue := buf[1:]\n\tbinary.LittleEndian.PutUint64(value, uint64(x))\n\tvar length byte\n\tfor length = 8; length > 0 && value[length-1] == 0; length-- {\n\t}\n\tbuf[0] = length\n\treturn buf[:length+1]\n}\n\nfunc EncodeLenByte(out *[]byte, buf []byte) *[]byte {\n\t*out = append(append(*out, EncodeLength(int64(len(buf)))...), buf...)\n\treturn out\n}\n\n// EncodeLength encodes int64 number to []byte. If it is less than 128 then it returns []byte{length}.\n// Otherwise, it returns (0x80 | len of int64) + int64 as BigEndian []byte\n//\n//\t67 => 0x43\n//\t1024 => 0x820400\n//\t1000000 => 0x830f4240\nfunc EncodeLength(length int64) []byte {\n\tif length >= 0 && length <= 127 {\n\t\treturn []byte{byte(length)}\n\t}\n\tbuf := make([]byte, 9)\n\tbinary.BigEndian.PutUint64(buf[1:], uint64(length))\n\ti := 1\n\tfor ; buf[i] == 0 && i < 8; i++ {\n\t}\n\tbuf[0] = 0x80 | byte(9-i)\n\treturn append(buf[:1], buf[i:]...)\n}\n\n// DecodeLenInt64 gets int64 from []byte and shift the slice. The []byte should  be\n// encoded with EncodeLengthPlusInt64.\nfunc DecodeLenInt64(data *[]byte) (int64, error) {\n\tif len(*data) == 0 {\n\t\treturn 0, nil\n\t}\n\tlength := int((*data)[0]) + 1\n\tif len(*data) < length {\n\t\tlog.WithFields(log.Fields{\"data_length\": len(*data), \"length\": length, \"type\": consts.UnmarshallingError}).Error(\"length of data is smaller then encoded length\")\n\t\treturn 0, fmt.Errorf(`length of data %d < %d`, len(*data), length)\n\t}\n\tbuf := make([]byte, 8)\n\tcopy(buf, (*data)[1:length])\n\tx := int64(binary.LittleEndian.Uint64(buf))\n\t*data = (*data)[length:]\n\treturn x, nil\n}\n\nfunc DecodeLenInt64Buf(buf *bytes.Buffer) (int64, error) {\n\tif buf.Len() == 0 {\n\t\treturn 0, nil\n\t}\n\n\tval, err := buf.ReadByte()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"cannot read bytes from buffer\")\n\t\treturn 0, err\n\t}\n\n\tlength := int(val)\n\tif buf.Len() < length {\n\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"data_length\": buf.Len(), \"length\": length}).Error(\"length of data is smaller then encoded length\")\n\t\treturn 0, fmt.Errorf(`length of data %d < %d`, buf.Len(), length)\n\t}\n\tdata := make([]byte, 8)\n\tcopy(data, buf.Next(length))\n\n\treturn int64(binary.LittleEndian.Uint64(data)), nil\n\n}\n\n// DecodeLength decodes []byte to int64 and shifts buf. Bytes must be encoded with EncodeLength function.\n//\n//\t0x43 => 67\n//\t0x820400 => 1024\n//\t0x830f4240 => 1000000\nfunc DecodeLength(buf *[]byte) (ret int64, err error) {\n\tif len(*buf) == 0 {\n\t\treturn\n\t}\n\tlength := (*buf)[0]\n\tif (length & 0x80) != 0 {\n\t\tlength &= 0x7F\n\t\tif len(*buf) < int(length+1) {\n\t\t\tlog.WithFields(log.Fields{\"data_length\": len(*buf), \"length\": int(length + 1)}).Error(\"length of data is smaller then encoded length\")\n\t\t\treturn 0, fmt.Errorf(`input slice has small size`)\n\t\t}\n\t\tret = int64(binary.BigEndian.Uint64(append(make([]byte, 8-length), (*buf)[1:length+1]...)))\n\t} else {\n\t\tret = int64(length)\n\t\tlength = 0\n\t}\n\t*buf = (*buf)[length+1:]\n\treturn\n}\n\nfunc DecodeLengthBuf(buf *bytes.Buffer) (int, error) {\n\tif buf.Len() == 0 {\n\t\treturn 0, nil\n\t}\n\n\tlength, err := buf.ReadByte()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"cannot read bytes from buffer\")\n\t\treturn 0, err\n\t}\n\n\tif (length & 0x80) == 0 {\n\t\treturn int(length), nil\n\t}\n\n\tlength &= 0x7F\n\tif buf.Len() < int(length) {\n\t\tlog.WithFields(log.Fields{\"data_length\": buf.Len(), \"length\": int(length), \"type\": consts.UnmarshallingError}).Error(\"length of data is smaller then encoded length\")\n\t\treturn 0, fmt.Errorf(`input slice has small size`)\n\t}\n\n\tn := int(binary.BigEndian.Uint64(append(make([]byte, 8-length), buf.Next(int(length))...)))\n\tif n < 0 {\n\t\treturn 0, fmt.Errorf(`input slice has negative size`)\n\t}\n\n\treturn n, nil\n}\n\nfunc DecodeBytesBuf(buf *bytes.Buffer) ([]byte, error) {\n\tn, err := DecodeLengthBuf(buf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif buf.Len() < n {\n\t\treturn nil, ErrSliceSize\n\t}\n\treturn buf.Next(n), nil\n}\n\n// BinMarshal converts v parameter to []byte slice.\nfunc BinMarshal(out *[]byte, v any) (*[]byte, error) {\n\tvar err error\n\n\tt := reflect.ValueOf(v)\n\tif *out == nil {\n\t\t*out = make([]byte, 0, 2048)\n\t}\n\n\tswitch t.Kind() {\n\tcase reflect.Uint8, reflect.Int8:\n\t\t*out = append(*out, uint8(t.Uint()))\n\tcase reflect.Uint32:\n\t\ttmp := make([]byte, 4)\n\t\tbinary.BigEndian.PutUint32(tmp, uint32(t.Uint()))\n\t\t*out = append(*out, tmp...)\n\tcase reflect.Int32:\n\t\tif uint32(t.Int()) < 128 {\n\t\t\t*out = append(*out, uint8(t.Int()))\n\t\t} else {\n\t\t\tvar i uint8\n\t\t\ttmp := make([]byte, 4)\n\t\t\tbinary.BigEndian.PutUint32(tmp, uint32(t.Int()))\n\t\t\tfor ; i < 4; i++ {\n\t\t\t\tif tmp[i] != uint8(0) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\t*out = append(*out, 128+4-i)\n\t\t\t*out = append(*out, tmp[i:]...)\n\t\t}\n\tcase reflect.Float64:\n\t\tbin := float2Bytes(t.Float())\n\t\t*out = append(*out, bin...)\n\tcase reflect.Int64:\n\t\tEncodeLenInt64(out, t.Int())\n\tcase reflect.Uint64:\n\t\ttmp := make([]byte, 8)\n\t\tbinary.BigEndian.PutUint64(tmp, t.Uint())\n\t\t*out = append(*out, tmp...)\n\tcase reflect.String:\n\t\t*out = append(append(*out, EncodeLength(int64(t.Len()))...), []byte(t.String())...)\n\tcase reflect.Struct:\n\t\tfor i := 0; i < t.NumField(); i++ {\n\t\t\tif out, err = BinMarshal(out, t.Field(i).Interface()); err != nil {\n\t\t\t\treturn out, err\n\t\t\t}\n\t\t}\n\tcase reflect.Slice:\n\t\t*out = append(append(*out, EncodeLength(int64(t.Len()))...), t.Bytes()...)\n\tcase reflect.Ptr:\n\t\tif out, err = BinMarshal(out, t.Elem().Interface()); err != nil {\n\t\t\treturn out, err\n\t\t}\n\tdefault:\n\t\treturn out, fmt.Errorf(`unsupported type of BinMarshal`)\n\t}\n\treturn out, nil\n}\n\nfunc BinUnmarshalBuff(buf *bytes.Buffer, v any) error {\n\tt := reflect.ValueOf(v)\n\tif t.Kind() == reflect.Ptr {\n\t\tt = t.Elem()\n\t}\n\tif buf.Len() == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": \"input slice is empty\"}).Error(\"input slice is empty\")\n\t\treturn fmt.Errorf(`input slice is empty`)\n\t}\n\tswitch t.Kind() {\n\tcase reflect.Uint8, reflect.Int8:\n\t\tval, err := buf.ReadByte()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tt.SetUint(uint64(val))\n\n\tcase reflect.Uint32:\n\t\tt.SetUint(uint64(binary.BigEndian.Uint32(buf.Next(4))))\n\n\tcase reflect.Int32:\n\t\tval, err := buf.ReadByte()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading bytes from buffer\")\n\t\t\treturn err\n\t\t}\n\t\tif val < 128 {\n\t\t\tt.SetInt(int64(val))\n\t\t} else {\n\t\t\tvar i uint8\n\t\t\tsize := val - 128\n\t\t\ttmp := make([]byte, 4)\n\t\t\tif buf.Len() <= int(size) || size > 4 {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"data_length\": buf.Len(), \"length\": int(size)}).Error(\"bin unmarshalling int32\")\n\t\t\t\treturn fmt.Errorf(`wrong input data`)\n\t\t\t}\n\t\t\tfor ; i < size; i++ {\n\t\t\t\tbyteVal, err := buf.ReadByte()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading bytes from buffer\")\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttmp[4-size+i] = byteVal\n\t\t\t}\n\t\t\tt.SetInt(int64(binary.BigEndian.Uint32(tmp)))\n\t\t}\n\tcase reflect.Float64:\n\t\tt.SetFloat(bytes2Float(buf.Next(8)))\n\n\tcase reflect.Int64:\n\t\tval, err := DecodeLenInt64Buf(buf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tt.SetInt(val)\n\n\tcase reflect.Uint64:\n\t\tt.SetUint(binary.BigEndian.Uint64(buf.Next(8)))\n\n\tcase reflect.String:\n\t\tval, err := DecodeLengthBuf(buf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif buf.Len() < val {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"data_length\": buf.Len(), \"length\": val}).Error(\"bin unmarshalling string\")\n\t\t\treturn fmt.Errorf(`input slice is short`)\n\t\t}\n\t\tt.SetString(string(buf.Next(val)))\n\n\tcase reflect.Struct:\n\t\tfor i := 0; i < t.NumField(); i++ {\n\t\t\tif err := BinUnmarshalBuff(buf, t.Field(i).Addr().Interface()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase reflect.Slice:\n\t\tval, err := DecodeLengthBuf(buf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif buf.Len() < val {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"data_length\": buf.Len(), \"length\": val}).Error(\"bin unmarshalling slice\")\n\t\t\treturn fmt.Errorf(`input slice is short`)\n\t\t}\n\t\tt.SetBytes(buf.Next(val))\n\n\tdefault:\n\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"value_type\": t.Kind()}).Error(\"BinUnmrashal unsupported type\")\n\t\treturn fmt.Errorf(`unsupported type of BinUnmarshal %v`, t.Kind())\n\t}\n\treturn nil\n\n}\n\n// BinUnmarshal converts []byte slice which has been made with BinMarshal to v\nfunc BinUnmarshal(out *[]byte, v any) error {\n\tt := reflect.ValueOf(v)\n\tif t.Kind() == reflect.Ptr {\n\t\tt = t.Elem()\n\t}\n\tif len(*out) == 0 {\n\t\treturn fmt.Errorf(`input slice is empty`)\n\t}\n\tswitch t.Kind() {\n\tcase reflect.Uint8, reflect.Int8:\n\t\tval := uint64((*out)[0])\n\t\tt.SetUint(val)\n\t\t*out = (*out)[1:]\n\tcase reflect.Uint32:\n\t\tt.SetUint(uint64(binary.BigEndian.Uint32((*out)[:4])))\n\t\t*out = (*out)[4:]\n\tcase reflect.Int32:\n\t\tval := (*out)[0]\n\t\tif val < 128 {\n\t\t\tt.SetInt(int64(val))\n\t\t\t*out = (*out)[1:]\n\t\t} else {\n\t\t\tvar i uint8\n\t\t\tsize := val - 128\n\t\t\ttmp := make([]byte, 4)\n\t\t\tif len(*out) <= int(size) || size > 4 {\n\t\t\t\treturn fmt.Errorf(`wrong input data`)\n\t\t\t}\n\t\t\tfor ; i < size; i++ {\n\t\t\t\ttmp[4-size+i] = (*out)[i+1]\n\t\t\t}\n\t\t\tt.SetInt(int64(binary.BigEndian.Uint32(tmp)))\n\t\t\t*out = (*out)[size+1:]\n\t\t}\n\tcase reflect.Float64:\n\t\tt.SetFloat(bytes2Float((*out)[:8]))\n\t\t*out = (*out)[8:]\n\tcase reflect.Int64:\n\t\tval, err := DecodeLenInt64(out)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tt.SetInt(val)\n\tcase reflect.Uint64:\n\t\tt.SetUint(binary.BigEndian.Uint64((*out)[:8]))\n\t\t*out = (*out)[8:]\n\tcase reflect.String:\n\t\tval, err := DecodeLength(out)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(*out) < int(val) {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"data_length\": len(*out), \"length\": int(val)}).Error(\"input slice is short\")\n\t\t\treturn fmt.Errorf(`input slice is short`)\n\t\t}\n\t\tt.SetString(string((*out)[:val]))\n\t\t*out = (*out)[val:]\n\tcase reflect.Struct:\n\t\tfor i := 0; i < t.NumField(); i++ {\n\t\t\tif err := BinUnmarshal(out, t.Field(i).Addr().Interface()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase reflect.Slice:\n\t\tval, err := DecodeLength(out)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(*out) < int(val) {\n\t\t\treturn fmt.Errorf(`input slice is short`)\n\t\t}\n\t\tt.SetBytes((*out)[:val])\n\t\t*out = (*out)[val:]\n\tdefault:\n\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"value_type\": t.Kind()}).Error(\"BinUnmrashal unsupported type\")\n\t\treturn fmt.Errorf(`unsupported type of BinUnmarshal %v`, t.Kind())\n\t}\n\treturn nil\n}\n\n// Sanitize deletes unaccessable characters from input string\nfunc Sanitize(name string, available string) string {\n\tout := make([]rune, 0, len(name))\n\tfor _, ch := range name {\n\t\tif ch > 127 || (ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') ||\n\t\t\t(ch >= 'A' && ch <= 'Z') || strings.IndexRune(available, ch) >= 0 {\n\t\t\tout = append(out, ch)\n\t\t}\n\t}\n\treturn string(out)\n}\n\n// SanitizeScript deletes unaccessable characters from input string\nfunc SanitizeScript(input string) string {\n\treturn strings.Replace(strings.Replace(input, `<script`, `&lt;script`, -1), `script>`, `script&gt;`, -1)\n}\n\n// SanitizeName deletes unaccessable characters from name string\nfunc SanitizeName(input string) string {\n\treturn Sanitize(input, `- `)\n}\n\n// SanitizeNumber deletes unaccessable characters from number or name string\nfunc SanitizeNumber(input string) string {\n\treturn Sanitize(input, `+.- `)\n}\n\nfunc EscapeSQL(name string) string {\n\treturn strings.Replace(strings.Replace(strings.Replace(name, `\"`, `\"\"`, -1),\n\t\t`;`, ``, -1), `'`, `''`, -1)\n}\n\n// EscapeName deletes unaccessable characters for input name(s)\nfunc EscapeName(name string) string {\n\tout := make([]byte, 1, len(name)+2)\n\tout[0] = '\"'\n\tavailable := `() ,`\n\tfor _, ch := range []byte(name) {\n\t\tif (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') ||\n\t\t\t(ch >= 'A' && ch <= 'Z') || strings.IndexByte(available, ch) >= 0 {\n\t\t\tout = append(out, ch)\n\t\t}\n\t}\n\tif strings.IndexAny(string(out), available) >= 0 {\n\t\treturn string(out[1:])\n\t}\n\treturn string(append(out, '\"'))\n}\n\n// Float2Bytes converts float64 to []byte\nfunc float2Bytes(float float64) []byte {\n\tret := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(ret, math.Float64bits(float))\n\treturn ret\n}\n\n// Bytes2Float converts []byte to float64\nfunc bytes2Float(bytes []byte) float64 {\n\treturn math.Float64frombits(binary.LittleEndian.Uint64(bytes))\n}\n\n// UInt32ToStr converts uint32 to string\nfunc UInt32ToStr(num uint32) string {\n\treturn strconv.FormatInt(int64(num), 10)\n}\n\n// Int64ToStr converts int64 to string\nfunc Int64ToStr(num int64) string {\n\treturn strconv.FormatInt(num, 10)\n}\n\n// Int64ToByte converts int64 to []byte\nfunc Int64ToByte(num int64) []byte {\n\treturn []byte(strconv.FormatInt(num, 10))\n}\n\n// IntToStr converts integer to string\nfunc IntToStr(num int) string {\n\treturn strconv.Itoa(num)\n}\n\n// DecToBin converts interface to []byte\nfunc DecToBin(v any, sizeBytes int64) []byte {\n\tvar dec int64\n\tswitch v.(type) {\n\tcase int:\n\t\tdec = int64(v.(int))\n\tcase int64:\n\t\tdec = v.(int64)\n\tcase uint64:\n\t\tdec = int64(v.(uint64))\n\tcase string:\n\t\tdec = StrToInt64(v.(string))\n\t}\n\tHex := fmt.Sprintf(\"%0\"+Int64ToStr(sizeBytes*2)+\"x\", dec)\n\treturn HexToBin([]byte(Hex))\n}\n\n// BinToHex converts interface to hex []byte\nfunc BinToHex(v any) []byte {\n\tvar bin []byte\n\tswitch v.(type) {\n\tcase []byte:\n\t\tbin = v.([]byte)\n\tcase int64:\n\t\tbin = Int64ToByte(v.(int64))\n\tcase string:\n\t\tbin = []byte(v.(string))\n\t}\n\treturn []byte(fmt.Sprintf(\"%x\", bin))\n}\n\n// HexToBin converts hex interface to binary []byte\nfunc HexToBin(ihexdata any) []byte {\n\tvar hexdata string\n\tswitch ihexdata.(type) {\n\tcase []byte:\n\t\thexdata = string(ihexdata.([]byte))\n\tcase int64:\n\t\thexdata = Int64ToStr(ihexdata.(int64))\n\tcase string:\n\t\thexdata = ihexdata.(string)\n\t}\n\tvar str []byte\n\tstr, err := hex.DecodeString(hexdata)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"data\": hexdata, \"error\": err, \"type\": consts.ConversionError}).Error(\"decoding string to hex\")\n\t\tlog.Printf(\"HexToBin error: %s\", err)\n\t}\n\treturn str\n}\n\n// BinToDec converts input binary []byte to int64\nfunc BinToDec(bin []byte) int64 {\n\tvar a uint64\n\tl := len(bin)\n\tfor i, b := range bin {\n\t\tshift := uint64((l - i - 1) * 8)\n\t\ta |= uint64(b) << shift\n\t}\n\treturn int64(a)\n}\n\n// BinToDecBytesShift converts the input binary []byte to int64 and shifts the input bin\nfunc BinToDecBytesShift(bin *[]byte, num int64) int64 {\n\treturn BinToDec(BytesShift(bin, num))\n}\n\n// BytesShift returns the index bytes of the input []byte and shift str pointer\nfunc BytesShift(str *[]byte, index int64) (ret []byte) {\n\tif int64(len(*str)) < index || index == 0 {\n\t\t*str = (*str)[:0]\n\t\treturn []byte{}\n\t}\n\tret, *str = (*str)[:index], (*str)[index:]\n\treturn\n}\n\n// InterfaceToStr converts the interfaces to the string\nfunc InterfaceToStr(v any) (string, error) {\n\tvar str string\n\tif v == nil {\n\t\treturn ``, nil\n\t}\n\tswitch v.(type) {\n\tcase int:\n\t\tstr = IntToStr(v.(int))\n\tcase float64:\n\t\tstr = Float64ToStr(v.(float64))\n\tcase int64:\n\t\tstr = Int64ToStr(v.(int64))\n\tcase string:\n\t\tstr = v.(string)\n\tcase []byte:\n\t\tstr = string(v.([]byte))\n\tdefault:\n\t\tif reflect.TypeOf(v).String() == `map[string]interface {}` ||\n\t\t\treflect.TypeOf(v).String() == `*types.Map` {\n\t\t\tif out, err := json.Marshal(v); err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.JSONMarshallError}).Error(\"marshalling map for jsonb\")\n\t\t\t\treturn ``, err\n\t\t\t} else {\n\t\t\t\tstr = string(out)\n\t\t\t}\n\t\t} else if reflect.TypeOf(v).String() == `decimal.Decimal` {\n\t\t\tstr = v.(decimal.Decimal).String()\n\t\t}\n\t}\n\treturn str, nil\n}\n\n// InterfaceSliceToStr converts the slice of interfaces to the slice of strings\nfunc InterfaceSliceToStr(i []any) (strs []string, err error) {\n\tvar val string\n\tfor _, v := range i {\n\t\tval, err = InterfaceToStr(v)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tstrs = append(strs, val)\n\t}\n\treturn\n}\n\n// InterfaceToFloat64 converts the interfaces to the float64\nfunc InterfaceToFloat64(i any) float64 {\n\tvar result float64\n\tswitch i.(type) {\n\tcase int:\n\t\tresult = float64(i.(int))\n\tcase float64:\n\t\tresult = i.(float64)\n\tcase int64:\n\t\tresult = float64(i.(int64))\n\tcase string:\n\t\tresult = StrToFloat64(i.(string))\n\tcase []byte:\n\t\tresult = BytesToFloat64(i.([]byte))\n\t}\n\treturn result\n}\n\n// BytesShiftReverse gets []byte from the end of the input and cut the input pointer to []byte\nfunc BytesShiftReverse(str *[]byte, v any) []byte {\n\tvar index int64\n\tswitch v.(type) {\n\tcase int:\n\t\tindex = int64(v.(int))\n\tcase int64:\n\t\tindex = v.(int64)\n\t}\n\n\tvar substr []byte\n\tslen := int64(len(*str))\n\tif slen < index {\n\t\tindex = slen\n\t}\n\tsubstr = (*str)[slen-index:]\n\t*str = (*str)[:slen-index]\n\treturn substr\n}\n\n// StrToInt64 converts string to int64\nfunc StrToInt64(s string) int64 {\n\tret, _ := strconv.ParseInt(s, 10, 64)\n\treturn ret\n}\n\n// BytesToInt64 converts []bytes to int64\nfunc BytesToInt64(s []byte) int64 {\n\tret, _ := strconv.ParseInt(string(s), 10, 64)\n\treturn ret\n}\n\n// StrToUint64 converts string to the unsinged int64\nfunc StrToUint64(s string) uint64 {\n\tret, _ := strconv.ParseUint(s, 10, 64)\n\treturn ret\n}\n\n// StrToInt converts string to integer\nfunc StrToInt(s string) int {\n\ti, _ := strconv.Atoi(s)\n\treturn i\n}\n\n// Float64ToStr converts float64 to string\nfunc Float64ToStr(f float64) string {\n\treturn strconv.FormatFloat(f, 'f', 13, 64)\n}\n\n// StrToFloat64 converts string to float64\nfunc StrToFloat64(s string) float64 {\n\tFloat64, _ := strconv.ParseFloat(s, 64)\n\treturn Float64\n}\n\n// BytesToFloat64 converts []byte to float64\nfunc BytesToFloat64(s []byte) float64 {\n\tFloat64, _ := strconv.ParseFloat(string(s), 64)\n\treturn Float64\n}\n\n// BytesToInt converts []byte to integer\nfunc BytesToInt(s []byte) int {\n\ti, _ := strconv.Atoi(string(s))\n\treturn i\n}\n\n// StrToMoney rounds money string to float64\nfunc StrToMoney(str string) float64 {\n\tind := strings.Index(str, \".\")\n\tvar newStr string\n\tif ind != -1 {\n\t\tend := 2\n\t\tif len(str[ind+1:]) > 1 {\n\t\t\tend = 3\n\t\t}\n\t\tnewStr = str[:ind] + \".\" + str[ind+1:ind+end]\n\t} else {\n\t\tnewStr = str\n\t}\n\treturn StrToFloat64(newStr)\n}\n\n// EncodeLengthPlusData encoding interface into []byte\nfunc EncodeLengthPlusData(idata any) []byte {\n\tvar data []byte\n\tswitch idata.(type) {\n\tcase int64:\n\t\tdata = Int64ToByte(idata.(int64))\n\tcase string:\n\t\tdata = []byte(idata.(string))\n\tcase []byte:\n\t\tdata = idata.([]byte)\n\t}\n\t//log.Debug(\"data: %x\", data)\n\t//log.Debug(\"len data: %d\", len(data))\n\treturn append(EncodeLength(int64(len(data))), data...)\n}\n\n// FormatMoney converts minimal unit to legibility unit. For example, value * 10 ^ -digit\nfunc FormatMoney(exp string, digit int32) (string, error) {\n\tif len(exp) == 0 {\n\t\treturn `0`, nil\n\t}\n\tif strings.IndexByte(exp, '.') >= 0 {\n\t\treturn `0`, fmt.Errorf(`wrong money format %s`, exp)\n\t}\n\tif digit < 0 {\n\t\treturn `0`, fmt.Errorf(`digit must be positive`)\n\t}\n\tif len(exp) > consts.MoneyLength {\n\t\treturn `0`, fmt.Errorf(`too long money`)\n\t}\n\tretDec, err := decimal.NewFromString(exp)\n\tif err != nil {\n\t\treturn `0`, err\n\t}\n\treturn retDec.Shift(-digit).String(), nil\n}\n\n// EscapeForJSON replaces quote to slash and quote\nfunc EscapeForJSON(data string) string {\n\treturn strings.Replace(data, `\"`, `\\\"`, -1)\n}\n\n// ValidateEmail validates email\nfunc ValidateEmail(email string) bool {\n\tRe := regexp.MustCompile(`^(?i)[a-z0-9._%+\\-]+@[a-z0-9.\\-]+\\.[a-z]{2,4}$`)\n\treturn Re.MatchString(email)\n}\n\n// ParseName gets a state identifier and the name of the contract or table\n// from the full name like @[id]name\nfunc ParseName(in string) (id int64, name string) {\n\tre := regexp.MustCompile(`(?is)^@(\\d+)(\\w[_\\w\\d]*)$`)\n\tret := re.FindStringSubmatch(in)\n\tif len(ret) == 3 {\n\t\tid = StrToInt64(ret[1])\n\t\tname = ret[2]\n\t}\n\treturn\n}\n\n// ParseTable return\n// format 1:@[id]tblname -> parse id_tblname\n// format 2:[defaultEcosystem]_tblname\nfunc ParseTable(tblname string, defaultEcosystem int64) string {\n\tecosystem, name := ParseName(tblname)\n\tif ecosystem == 0 {\n\t\tif FirstEcosystemTables[tblname] {\n\t\t\tecosystem = 1\n\t\t} else {\n\t\t\tecosystem = defaultEcosystem\n\t\t}\n\t\tname = tblname\n\t}\n\treturn strings.ToLower(fmt.Sprintf(`%d_%s`, ecosystem, Sanitize(name, ``)))\n}\n\nfunc SubNodeParseTable(tblname string, defaultEcosystem int64) string {\n\tecosystem, name := ParseName(tblname)\n\tif ecosystem == 0 {\n\t\tif FirstEcosystemTables[tblname] {\n\t\t\tecosystem = 1\n\t\t} else {\n\t\t\tecosystem = defaultEcosystem\n\t\t}\n\t\tname = tblname\n\t}\n\t//return strings.ToLower(fmt.Sprintf(`%d_%s`, ecosystem, Sanitize(name, ``)))\n\treturn strings.ToLower(fmt.Sprintf(`%s`, Sanitize(name, ``)))\n}\n\n// SliceReverse reverses the slice of int64\nfunc SliceReverse(s []int64) []int64 {\n\tfor i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {\n\t\ts[i], s[j] = s[j], s[i]\n\t}\n\treturn s\n}\n\n// SortMap sorts map to the slice of maps\nfunc SortMap(m map[int64]string) []map[int64]string {\n\tvar keys []int\n\tfor k := range m {\n\t\tkeys = append(keys, int(k))\n\t}\n\tsort.Ints(keys)\n\tvar result []map[int64]string\n\tfor _, k := range keys {\n\t\tresult = append(result, map[int64]string{int64(k): m[int64(k)]})\n\t}\n\treturn result\n}\n\n// RSortMap sorts map to the reversed slice of maps\nfunc RSortMap(m map[int64]string) []map[int64]string {\n\n\tvar keys []int\n\tfor k := range m {\n\t\tkeys = append(keys, int(k))\n\t}\n\tsort.Sort(sort.Reverse(sort.IntSlice(keys)))\n\tvar result []map[int64]string\n\tfor _, k := range keys {\n\t\tresult = append(result, map[int64]string{int64(k): m[int64(k)]})\n\t}\n\treturn result\n}\n\n// InSliceString searches the string in the slice of strings\nfunc InSliceString(search string, slice []string) bool {\n\tfor _, v := range slice {\n\t\tif v == search {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// StripTags replaces < and > to &lt; and &gt;\nfunc StripTags(value string) string {\n\treturn strings.Replace(strings.Replace(value, `<`, `&lt;`, -1), `>`, `&gt;`, -1)\n}\n\n// IsLatin checks if the specified string contains only latin character, digits and '-', '_'.\nfunc IsLatin(name string) bool {\n\tfor _, ch := range []byte(name) {\n\t\tif !((ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') ||\n\t\t\t(ch >= 'A' && ch <= 'Z')) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Escape deletes unaccessable characters\nfunc Escape(data string) string {\n\tout := make([]rune, 0, len(data))\n\tavailable := `_ ,=!-'()\"?*$#{}<>: `\n\tfor _, ch := range []rune(data) {\n\t\tif (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') ||\n\t\t\t(ch >= 'A' && ch <= 'Z') || strings.IndexByte(available, byte(ch)) >= 0 ||\n\t\t\tunicode.IsLetter(ch) || ch >= 128 {\n\t\t\tout = append(out, ch)\n\t\t}\n\t}\n\treturn string(out)\n}\n\n// FieldToBytes returns the value of n-th field of v as []byte\nfunc FieldToBytes(v any, num int) []byte {\n\tt := reflect.ValueOf(v)\n\tret := make([]byte, 0, 2048)\n\tif t.Kind() == reflect.Struct && num < t.NumField() {\n\t\tfield := t.Field(num)\n\t\tswitch field.Kind() {\n\t\tcase reflect.Uint8, reflect.Uint32, reflect.Uint64:\n\t\t\tret = append(ret, []byte(fmt.Sprintf(\"%d\", field.Uint()))...)\n\t\tcase reflect.Int8, reflect.Int32, reflect.Int64:\n\t\t\tret = append(ret, []byte(fmt.Sprintf(\"%d\", field.Int()))...)\n\t\tcase reflect.Float64:\n\t\t\tret = append(ret, []byte(fmt.Sprintf(\"%f\", field.Float()))...)\n\t\tcase reflect.String:\n\t\t\tret = append(ret, []byte(field.String())...)\n\t\tcase reflect.Slice:\n\t\t\tret = append(ret, field.Bytes()...)\n\t\t\t//\t\tcase reflect.Ptr:\n\t\t\t//\t\tcase reflect.Struct:\n\t\t\t//\t\tdefault:\n\t\t}\n\t}\n\treturn ret\n}\n\n// NumString insert spaces between each three digits. 7123456 => 7 123 456\nfunc NumString(in string) string {\n\tif strings.IndexByte(in, '.') >= 0 {\n\t\tlr := strings.Split(in, `.`)\n\t\treturn NumString(lr[0]) + `.` + lr[1]\n\t}\n\tbuf := []byte(in)\n\tout := make([]byte, len(in)+4)\n\tfor len(buf) > 3 {\n\t\tout = append(append([]byte(` `), buf[len(buf)-3:]...), out...)\n\t\tbuf = buf[:len(buf)-3]\n\t}\n\treturn string(append(buf, out...))\n}\n\nfunc Round(num float64) int64 {\n\t//log.Debug(\"num\", num)\n\t//num += ROUND_FIX\n\t//\treturn int(StrToFloat64(Float64ToStr(num)) + math.Copysign(0.5, num))\n\t//log.Debug(\"num\", num)\n\treturn int64(num + math.Copysign(0.5, num))\n}\n\n// RoundWithPrecision rounds float64 value\nfunc RoundWithPrecision(num float64, precision int) float64 {\n\tnum += consts.RoundFix\n\toutput := math.Pow(10, float64(precision))\n\treturn float64(Round(num*output)) / output\n}\n\n// RoundWithoutPrecision is round float64 without precision\nfunc RoundWithoutPrecision(num float64) int64 {\n\t//log.Debug(\"num\", num)\n\t//num += ROUND_FIX\n\t//\treturn int(StrToFloat64(Float64ToStr(num)) + math.Copysign(0.5, num))\n\t//log.Debug(\"num\", num)\n\treturn int64(num + math.Copysign(0.5, num))\n}\n\n// ValueToInt converts interface (string or int64) to int64\nfunc ValueToInt(v any) (ret int64, err error) {\n\tswitch val := v.(type) {\n\tcase float64:\n\t\tret = int64(val)\n\tcase int64:\n\t\tret = val\n\tcase string:\n\t\tif len(val) == 0 {\n\t\t\treturn 0, nil\n\t\t}\n\t\tret, err = strconv.ParseInt(val, 10, 64)\n\t\tif err != nil {\n\t\t\terrText := err.Error()\n\t\t\tif strings.Contains(errText, `:`) {\n\t\t\t\terrText = errText[strings.LastIndexByte(errText, ':'):]\n\t\t\t} else {\n\t\t\t\terrText = ``\n\t\t\t}\n\t\t\terr = fmt.Errorf(`%s is not a valid integer %s`, val, errText)\n\t\t}\n\tcase decimal.Decimal:\n\t\tret = val.IntPart()\n\tcase json.Number:\n\t\tret, err = val.Int64()\n\tdefault:\n\t\tif v == nil {\n\t\t\treturn 0, nil\n\t\t}\n\t\terr = fmt.Errorf(`%v is not a valid integer`, val)\n\t}\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err,\n\t\t\t\"value\": fmt.Sprint(v)}).Error(\"converting value to int\")\n\t}\n\treturn\n}\n\nfunc ValueToDecimal(v any) (ret decimal.Decimal, err error) {\n\tswitch val := v.(type) {\n\tcase float64:\n\t\tret = decimal.NewFromFloat(val).Floor()\n\tcase string:\n\t\tret, err = decimal.NewFromString(val)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err, \"value\": val}).Error(\"converting value from string to decimal\")\n\t\t} else {\n\t\t\tret = ret.Floor()\n\t\t}\n\tcase int64:\n\t\tret = decimal.New(val, 0)\n\tdefault:\n\t\tret = val.(decimal.Decimal)\n\t}\n\treturn\n}\n\nfunc Int64ToDateStr(date int64, format string) string {\n\tt := time.Unix(date, 0)\n\treturn t.Format(format)\n}\n\nfunc Int64Toint(dat int64) (int, error) {\n\tstr := strconv.FormatInt(dat, 10)\n\treturn strconv.Atoi(str)\n}\n\nfunc MarshalJson(v any) string {\n\tbuff, err := json.Marshal(v)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"v\": v, \"error\": err}).Error(\"marshalJson error\")\n\t}\n\treturn string(buff)\n}\n"
  },
  {
    "path": "packages/daemons/block_generator.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/protocols\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/pkg/errors\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// BlockGenerator is daemon that generates blocks\nfunc BlockGenerator(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\tDBLock()\n\tdefer DBUnlock()\n\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\tif err == nil && len(candidateNodes) > 0 {\n\t\tsyspar.SetRunModel(consts.CandidateNodeMode)\n\t\treturn BlockGeneratorCandidate(ctx, d)\n\t}\n\tsyspar.SetRunModel(consts.HonorNodeMode)\n\td.sleepTime = time.Second\n\tif node.IsNodePaused() {\n\t\treturn nil\n\t}\n\n\tnodePosition, err := syspar.GetThisNodePosition()\n\tif err != nil {\n\t\t// we are not honor node and can't generate new blocks\n\t\td.sleepTime = syspar.GetMaxBlockTimeDuration()\n\t\td.logger.WithFields(log.Fields{\"type\": consts.JustWaiting, \"error\": err}).Debug(\"we are not honor node, sleep for 10 seconds\")\n\t\treturn nil\n\t}\n\n\t// we need fresh myNodePosition after locking\n\tnodePosition, err = syspar.GetThisNodePosition()\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting node position by key id\")\n\t\treturn err\n\t}\n\n\tbtc := protocols.NewBlockTimeCounter()\n\tst := time.Now()\n\tif exists, err := btc.BlockForTimeExists(st, int(nodePosition)); exists || err != nil {\n\t\treturn nil\n\t}\n\n\ttimeToGenerate, err := btc.TimeToGenerate(st, int(nodePosition))\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err, \"position\": nodePosition}).Debug(\"calculating block time\")\n\t\treturn err\n\t}\n\n\tif !timeToGenerate {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.JustWaiting}).Debug(\"not my generation time\")\n\t\treturn nil\n\t}\n\t//if !NtpDriftFlag {\n\t//\td.logger.WithFields(log.Fields{\"type\": consts.Ntpdate}).Error(\"ntp time not ntpdate\")\n\t//\treturn nil\n\t//}\n\n\t//var cf sqldb.Confirmation\n\t//cfg, err := cf.CheckAllowGenBlock()\n\t//if err != nil {\n\t//\td.logger.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Debug(\"confirmation block not allow\")\n\t//\treturn err\n\t//}\n\t//\n\t//if !cfg {\n\t//\td.logger.WithFields(log.Fields{\"type\": consts.JustWaiting}).Debug(\"not my confirmation time\")\n\t//\treturn nil\n\t//}\n\tprevBlock := &sqldb.InfoBlock{}\n\t_, err = prevBlock.Get()\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting previous block\")\n\t\treturn err\n\t}\n\n\tNodePrivateKey, NodePublicKey := utils.GetNodeKeys()\n\tif len(NodePrivateKey) < 1 {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node private key is empty\")\n\t\treturn errors.New(`node private key is empty`)\n\t}\n\n\tdtx := DelayedTx{\n\t\tprivateKey: NodePrivateKey,\n\t\tpublicKey:  NodePublicKey,\n\t\tlogger:     d.logger,\n\t\ttime:       st.Unix(),\n\t}\n\n\ttxs, err := dtx.RunForDelayBlockID(prevBlock.BlockID + 1)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttrs, classifyTxsMap, err := processTransactionsNew(d.logger, txs, st)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Block generation will be started only if we have transactions\n\tif len(trs) == 0 {\n\t\treturn nil\n\t}\n\n\theader := &types.BlockHeader{\n\t\tBlockId:       prevBlock.BlockID + 1,\n\t\tTimestamp:     st.Unix(),\n\t\tEcosystemId:   0,\n\t\tKeyId:         conf.Config.KeyID,\n\t\tNetworkId:     conf.Config.LocalConf.NetworkID,\n\t\tNodePosition:  nodePosition,\n\t\tVersion:       consts.BlockVersion,\n\t\tConsensusMode: consts.HonorNodeMode,\n\t}\n\n\tprev := &types.BlockHeader{\n\t\tBlockId:       prevBlock.BlockID,\n\t\tBlockHash:     prevBlock.Hash,\n\t\tRollbacksHash: prevBlock.RollbacksHash,\n\t}\n\n\terr = generateProcessBlockNew(header, prev, trs, classifyTxsMap)\n\tif err != nil {\n\t\treturn err\n\t}\n\t//go notificator.CheckTokenMovementLimits(nil, conf.Config.TokenMovement, header.BlockId)\n\treturn nil\n}\n\nfunc generateNextBlock(blockHeader, prevBlock *types.BlockHeader, trs [][]byte) ([]byte, error) {\n\treturn block.MarshallBlock(\n\t\ttypes.WithCurHeader(blockHeader),\n\t\ttypes.WithPrevHeader(prevBlock),\n\t\ttypes.WithTxFullData(trs))\n}\n\nfunc processTransactionsNew(logger *log.Entry, txs []*sqldb.Transaction, st time.Time) ([][]byte, map[int][]*transaction.Transaction, error) {\n\tclassifyTxsMap := make(map[int][]*transaction.Transaction)\n\tvar done = make(<-chan time.Time, 1)\n\tif syspar.IsHonorNodeMode() {\n\t\tbtc := protocols.NewBlockTimeCounter()\n\t\t_, endTime, err := btc.RangeByTime(st)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.TimeCalcError, \"error\": err}).Error(\"on getting end time of generation\")\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tdone = time.After(endTime.Sub(st))\n\t}\n\ttrs, err := sqldb.GetAllUnusedTransactions(nil, syspar.GetMaxTxCount()-len(txs))\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all unused transactions\")\n\t\treturn nil, nil, err\n\t}\n\n\tlimits := transaction.NewLimits(transaction.GetLetPreprocess())\n\n\ttype badTxStruct struct {\n\t\thash  []byte\n\t\tmsg   string\n\t\tkeyID int64\n\t}\n\n\tprocessBadTx := func(dbTx *sqldb.DbTransaction) chan badTxStruct {\n\t\tch := make(chan badTxStruct)\n\n\t\tgo func() {\n\t\t\tfor badTxItem := range ch {\n\t\t\t\ttransaction.BadTxForBan(badTxItem.keyID)\n\t\t\t\t_ = transaction.MarkTransactionBad(badTxItem.hash, badTxItem.msg)\n\t\t\t}\n\t\t}()\n\n\t\treturn ch\n\t}\n\n\ttxBadChan := processBadTx(nil)\n\n\tdefer func() {\n\t\tclose(txBadChan)\n\t}()\n\n\t// Checks preprocessing count limits\n\ttxList := make([][]byte, 0, len(trs))\n\ttxs = append(txs, trs...)\n\n\tallDelayedContract, err := sqldb.GetAllDelayedContract()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tvar contractNames []string\n\tfor _, contract := range allDelayedContract {\n\t\tcontractNames = append(contractNames, contract.Contract)\n\t}\n\n\tfor i, txItem := range txs {\n\t\tif syspar.IsHonorNodeMode() {\n\t\t\tselect {\n\t\t\tcase <-done:\n\t\t\t\treturn txList, classifyTxsMap, nil\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t\tbufTransaction := bytes.NewBuffer(txItem.Data)\n\t\ttr, err := transaction.UnmarshallTransaction(bufTransaction, true)\n\t\tif err != nil {\n\t\t\tif tr != nil {\n\t\t\t\ttxBadChan <- badTxStruct{hash: tr.Hash(), msg: err.Error(), keyID: tr.KeyID()}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := tr.Check(st.Unix()); err != nil {\n\t\t\ttxBadChan <- badTxStruct{hash: tr.Hash(), msg: err.Error(), keyID: tr.KeyID()}\n\t\t\tcontinue\n\t\t}\n\t\tif txItem.GetTransactionRateStopNetwork() {\n\t\t\tclassifyTxsMap[types.StopNetworkTxType] = append(classifyTxsMap[types.StopNetworkTxType], tr)\n\t\t\ttxList = append(txList[:0], txs[i].Data)\n\t\t\tbreak\n\t\t}\n\t\tif tr.IsSmartContract() {\n\t\t\terr = limits.CheckLimit(tr.Inner)\n\t\t\tif errors.Cause(err) == transaction.ErrLimitStop && i > 0 {\n\t\t\t\tbreak\n\t\t\t} else if err != nil {\n\t\t\t\tif err != transaction.ErrLimitSkip {\n\t\t\t\t\ttxBadChan <- badTxStruct{hash: tr.Hash(), msg: err.Error(), keyID: tr.KeyID()}\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif tr.Type() == types.TransferSelfTxType {\n\t\t\t\tclassifyTxsMap[types.TransferSelfTxType] = append(classifyTxsMap[types.TransferSelfTxType], tr)\n\t\t\t\ttxList = append(txList, txs[i].Data)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif tr.Type() == types.UtxoTxType {\n\t\t\t\tclassifyTxsMap[types.UtxoTxType] = append(classifyTxsMap[types.UtxoTxType], tr)\n\t\t\t\ttxList = append(txList, txs[i].Data)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif utils.StringInSlice(contractNames, tr.SmartContract().TxContract.Name) {\n\t\t\t\tclassifyTxsMap[types.DelayTxType] = append(classifyTxsMap[types.DelayTxType], tr)\n\t\t\t\ttxList = append(txList, txs[i].Data)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tclassifyTxsMap[types.SmartContractTxType] = append(classifyTxsMap[types.SmartContractTxType], tr)\n\t\t}\n\t\ttxList = append(txList, txs[i].Data)\n\t}\n\treturn txList, classifyTxsMap, nil\n}\n"
  },
  {
    "path": "packages/daemons/block_generator_candidate.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"math\"\n\t\"sort\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc BlockGeneratorCandidate(ctx context.Context, d *daemon) error {\n\tdefer func() {\n\t\td.sleepTime = syspar.GetMaxBlockTimeDuration()\n\t}()\n\tif node.IsNodePaused() {\n\t\treturn nil\n\t}\n\tprevBlock := &sqldb.InfoBlock{}\n\t_, err := prevBlock.Get()\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting previous block\")\n\t\treturn err\n\t}\n\tNodePrivateKey, NodePublicKey := utils.GetNodeKeys()\n\tif len(NodePrivateKey) < 1 {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node private key is empty\")\n\t\treturn errors.New(`node private key is empty`)\n\t}\n\tif len(NodePublicKey) < 1 {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node public key is empty\")\n\t\treturn errors.New(`node public key is empty`)\n\t}\n\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"getting candidate node list\")\n\t\treturn err\n\t}\n\tcurrentCandidateNode, nodePosition := GetThisNodePosition(candidateNodes, prevBlock)\n\tif !nodePosition {\n\t\td.sleepTime = 4 * time.Second\n\t\td.logger.WithFields(log.Fields{\"type\": consts.JustWaiting, \"error\": err}).Debug(\"we are not honor node, sleep for 10 seconds\")\n\t\treturn nil\n\t}\n\tst := time.Now()\n\n\tdtx := DelayedTx{\n\t\tprivateKey: NodePrivateKey,\n\t\tpublicKey:  NodePublicKey,\n\t\tlogger:     d.logger,\n\t\ttime:       st.Unix(),\n\t}\n\ttxs, err := dtx.RunForDelayBlockID(prevBlock.BlockID + 1)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttrs, classifyTxsMap, err := processTransactionsNew(d.logger, txs, st)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Block generation will be started only if we have transactions\n\tif len(trs) == 0 {\n\t\treturn nil\n\t}\n\tlastBlockInterval := time.Unix(prevBlock.Time, 0)\n\ttimeDifference := st.Sub(lastBlockInterval)\n\tif timeDifference <= syspar.GetMaxBlockTimeDuration() {\n\t\ttime.Sleep(syspar.GetMaxBlockTimeDuration() - timeDifference)\n\t\tst = time.Now()\n\t}\n\n\tnodes := make([]types.BlockCandidateNode, len(candidateNodes))\n\tfor i, candidateNode := range candidateNodes {\n\t\tbcn := types.BlockCandidateNode{\n\t\t\tID:         candidateNode.ID,\n\t\t\tReplyCount: candidateNode.ReplyCount,\n\t\t}\n\t\tnodes[i] = bcn\n\t}\n\tcandidateNodesByte, _ := json.Marshal(nodes)\n\n\theader := &types.BlockHeader{\n\t\tBlockId:        prevBlock.BlockID + 1,\n\t\tTimestamp:      st.Unix(),\n\t\tEcosystemId:    0,\n\t\tKeyId:          conf.Config.KeyID,\n\t\tNetworkId:      conf.Config.LocalConf.NetworkID,\n\t\tNodePosition:   currentCandidateNode.ID,\n\t\tVersion:        consts.BlockVersion,\n\t\tConsensusMode:  consts.CandidateNodeMode,\n\t\tCandidateNodes: candidateNodesByte,\n\t}\n\tprev := &types.BlockHeader{\n\t\tBlockId:       prevBlock.BlockID,\n\t\tBlockHash:     prevBlock.Hash,\n\t\tRollbacksHash: prevBlock.RollbacksHash,\n\t}\n\n\terr = generateProcessBlockNew(header, prev, trs, classifyTxsMap)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc GetThisNodePosition(candidateNodes sqldb.CandidateNodes, prevBlock *sqldb.InfoBlock) (sqldb.CandidateNode, bool) {\n\tcandidateNode := sqldb.CandidateNode{}\n\tif len(candidateNodes) == 0 {\n\n\t\tfirstBlock, err := syspar.GetFirstBlockData()\n\t\tif err != nil {\n\t\t\treturn candidateNode, false\n\t\t}\n\t\tnodePubKey := syspar.GetNodePubKey()\n\t\tif bytes.Equal(firstBlock.NodePublicKey, nodePubKey) {\n\t\t\tcandidateNode.ID = 0\n\t\t\tcandidateNode.NodePubKey = hex.EncodeToString(nodePubKey)\n\t\t\tsyspar.SetRunModel(consts.HonorNodeMode)\n\t\t\treturn candidateNode, true\n\t\t}\n\t\treturn candidateNode, false\n\t}\n\n\tif len(candidateNodes) == 1 {\n\t\tnodePubKey := candidateNodes[0].NodePubKey\n\t\tpk, err := hex.DecodeString(nodePubKey)\n\t\tif err != nil {\n\t\t\treturn candidateNode, false\n\t\t}\n\t\tpk = crypto.CutPub(pk)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"decoding node private key from hex\")\n\t\t\treturn candidateNode, false\n\t\t}\n\t\tif bytes.Equal(pk, syspar.GetNodePubKey()) {\n\t\t\treturn candidateNodes[0], true\n\t\t}\n\t\treturn candidateNode, false\n\t}\n\n\tif len(candidateNodes) == 2 {\n\t\t_, NodePublicKey := utils.GetNodeKeys()\n\t\tNodePublicKey = \"04\" + NodePublicKey\n\n\t\tcompare := func(c []sqldb.CandidateNode) (sqldb.CandidateNode, bool) {\n\t\t\tvar (\n\t\t\t\tgenerateBlockNode   sqldb.CandidateNode\n\t\t\t\tisGenerateBlockNode bool\n\t\t\t\textNode             bool\n\t\t\t\tnode1               = candidateNodes[0]\n\t\t\t\tnode2               = candidateNodes[1]\n\t\t\t)\n\t\t\tfor i := 0; i < len(c); i++ {\n\t\t\t\tif prevBlock.NodePosition == strconv.FormatInt(c[i].ID, 10) {\n\t\t\t\t\textNode = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif extNode {\n\t\t\t\tfor _, node := range c {\n\t\t\t\t\tif NodePublicKey == node.NodePubKey && prevBlock.NodePosition != strconv.FormatInt(node.ID, 10) {\n\t\t\t\t\t\tisGenerateBlockNode = true\n\t\t\t\t\t\tgenerateBlockNode = node\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn generateBlockNode, isGenerateBlockNode\n\t\t\t}\n\t\t\tgenerateBlockNode = node1\n\t\t\tswitch node1.ReferendumTotal.Cmp(node2.ReferendumTotal) {\n\t\t\tcase 0:\n\t\t\t\tswitch node1.EarnestTotal.Cmp(node2.EarnestTotal) {\n\t\t\t\tcase 0:\n\t\t\t\t\tif node1.ReplyCount < node2.ReplyCount {\n\t\t\t\t\t\tgenerateBlockNode = node2\n\t\t\t\t\t} else if node1.ReplyCount == node2.ReplyCount {\n\t\t\t\t\t\tif node1.DateReply < node2.DateReply {\n\t\t\t\t\t\t\tgenerateBlockNode = node2\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tcase -1:\n\t\t\t\t\tgenerateBlockNode = node2\n\t\t\t\t}\n\t\t\tcase -1:\n\t\t\t\tgenerateBlockNode = node2\n\t\t\t}\n\t\t\treturn generateBlockNode, generateBlockNode.NodePubKey == NodePublicKey\n\t\t}\n\n\t\treturn compare(candidateNodes)\n\t}\n\tif len(candidateNodes) > 2 {\n\t\tcandidateNodesSqrt := math.Sqrt(float64(len(candidateNodes)))\n\t\tcandidateNodesCeil := math.Ceil(candidateNodesSqrt)\n\t\tstartBlockId := prevBlock.BlockID - int64(candidateNodesCeil)\n\t\tsubBlocks, err := sqldb.GetBlockchain(startBlockId, prevBlock.BlockID, sqldb.OrderASC)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting recent block\")\n\t\t\treturn candidateNode, false\n\t\t}\n\t\tsize := len(candidateNodes)\n\t\tnodeCount := len(candidateNodes)\n\t\tfor _, subBlock := range subBlocks {\n\t\t\tfor j := 0; j < size; j++ {\n\t\t\t\tif candidateNodes[j].ID == subBlock.NodePosition {\n\t\t\t\t\tcandidateNodes = append(candidateNodes[:j], candidateNodes[j+1:]...)\n\t\t\t\t\tsize = len(candidateNodes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsort.Sort(candidateNodes)\n\t\tif len(candidateNodes) > 0 {\n\t\t\tvar (\n\t\t\t\tmaxIndex    int\n\t\t\t\tisHonorNode bool\n\t\t\t)\n\t\t\tfor i, node := range candidateNodes {\n\t\t\t\tisHonorNode = agreeCount(int64(nodeCount), node.ReplyCount)\n\t\t\t\tif isHonorNode {\n\t\t\t\t\tmaxIndex = i\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\t_, NodePublicKey := utils.GetNodeKeys()\n\t\t\tif len(NodePublicKey) < 1 {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node public key is empty\")\n\t\t\t\treturn candidateNode, false\n\t\t\t}\n\t\t\tNodePublicKey = \"04\" + NodePublicKey\n\t\t\tif isHonorNode {\n\t\t\t\tif NodePublicKey == candidateNodes[maxIndex].NodePubKey {\n\t\t\t\t\treturn candidateNodes[maxIndex], true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn candidateNode, false\n}\n\nfunc agreeCount(candidateNodes int64, replyCount int64) bool {\n\tlessReplyCount := math.Ceil(float64(candidateNodes) / 2)\n\tif replyCount >= int64(lessReplyCount) {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "packages/daemons/block_generator_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"encoding/hex\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tcallDelayedContract = \"CallDelayedContract\"\n\tfirstEcosystemID    = 1\n)\n\n// DelayedTx represents struct which works with delayed contracts\ntype DelayedTx struct {\n\tlogger     *log.Entry\n\tprivateKey string\n\tpublicKey  string\n\ttime       int64\n}\n\n// RunForDelayBlockID creates the transactions that need to be run for blockID\nfunc (dtx *DelayedTx) RunForDelayBlockID(blockID int64) ([]*sqldb.Transaction, error) {\n\tcontracts, err := sqldb.GetAllDelayedContractsForBlockID(blockID)\n\tif err != nil {\n\t\tdtx.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting delayed contracts for block\")\n\t\treturn nil, err\n\t}\n\ttxList := make([]*sqldb.Transaction, 0, len(contracts))\n\tfor _, c := range contracts {\n\t\ttx, err := dtx.createDelayTxByItem(c.Contract, c.KeyID, c.HighRate)\n\t\tif err != nil {\n\t\t\tdtx.logger.WithError(err).Debug(\"can't create transaction for delayed contract\")\n\t\t\treturn nil, err\n\t\t}\n\t\ttxList = append(txList, tx)\n\t}\n\n\treturn txList, nil\n}\n\nfunc (dtx *DelayedTx) createDelayTxByItem(name string, keyID, highRate int64) (*sqldb.Transaction, error) {\n\tvm := script.GetVM()\n\tcontract := smart.VMGetContract(vm, name, uint32(firstEcosystemID))\n\tsmartTx := types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(contract.Info().ID),\n\t\t\tEcosystemID: firstEcosystemID,\n\t\t\tKeyID:       keyID,\n\t\t\tTime:        dtx.time,\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tSignedBy: smart.PubToID(dtx.publicKey),\n\t\tParams:   map[string]any{},\n\t}\n\n\tprivateKey, err := hex.DecodeString(dtx.privateKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttxData, txHash, err := transaction.NewInternalTransaction(smartTx, privateKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn transaction.CreateDelayTransactionHighRate(txData, txHash, keyID, highRate), nil\n}\n"
  },
  {
    "path": "packages/daemons/blocks_collection.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\t\"github.com/IBAX-io/go-ibax/packages/rollback\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// BlocksCollection collects and parses blocks\nfunc BlocksCollection(ctx context.Context, d *daemon) error {\n\tif ctx.Err() != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.ContextError, \"error\": ctx.Err()}).Error(\"context error\")\n\t\treturn ctx.Err()\n\t}\n\n\treturn blocksCollection(ctx, d)\n}\n\nfunc blocksCollection(ctx context.Context, d *daemon) (err error) {\n\tif !atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\treturn nil\n\t}\n\tdefer atomic.StoreUint32(&d.atomic, 0)\n\n\t//if !NtpDriftFlag {\n\t//\td.logger.WithFields(log.Fields{\"type\": consts.Ntpdate}).Error(\"ntp time not ntpdate\")\n\t//\treturn nil\n\t//}\n\n\thost, maxBlockID, err := getHostWithMaxID(ctx, d.logger)\n\tif err != nil {\n\t\td.logger.WithError(err).Warn(\"on checking best host\")\n\t\treturn err\n\t}\n\n\tinfoBlock := &sqldb.InfoBlock{}\n\tfound, err := infoBlock.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting cur blockID\")\n\t\treturn err\n\t}\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound, \"error\": err}).Error(\"Info block not found\")\n\t\treturn errors.New(\"Info block not found\")\n\t}\n\n\tif infoBlock.BlockID >= maxBlockID {\n\t\tlog.WithFields(log.Fields{\"blockID\": infoBlock.BlockID, \"maxBlockID\": maxBlockID}).Debug(\"Max block is already in the host\")\n\t\treturn nil\n\t}\n\n\tDBLock()\n\tdefer func() {\n\t\tnode.NodeDoneUpdatingBlockchain()\n\t\tDBUnlock()\n\t}()\n\n\t// update our chain till maxBlockID from the host\n\treturn UpdateChain(ctx, d, host, maxBlockID)\n}\n\n// UpdateChain load from host all blocks from our last block to maxBlockID\nfunc UpdateChain(ctx context.Context, d *daemon, host string, maxBlockID int64) error {\n\t// get current block id from our blockchain\n\tcurBlock := &sqldb.InfoBlock{}\n\tif _, err := curBlock.Get(); err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting info block\")\n\t\treturn err\n\t}\n\n\tif ctx.Err() != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.ContextError, \"error\": ctx.Err()}).Error(\"context error\")\n\t\treturn ctx.Err()\n\t}\n\n\tplayRawBlock := func(rb []byte) error {\n\t\tvar lastBlockID, lastBlockTime int64\n\t\tvar err error\n\t\tvar bl *block.Block\n\t\tdefer func(err2 *error) {\n\t\t\tif err2 != nil {\n\t\t\t\tbanNodePause(host, lastBlockID, lastBlockTime, *err2)\n\t\t\t}\n\t\t}(&err)\n\t\tbl, err = block.ProcessBlockByBinData(rb, true)\n\t\tif err != nil {\n\t\t\td.logger.WithFields(log.Fields{\"error\": err, \"type\": consts.BlockError}).Error(\"processing block\")\n\t\t\treturn err\n\t\t}\n\n\t\tcurBlock := &sqldb.InfoBlock{}\n\t\tif _, err = curBlock.Get(); err != nil {\n\t\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting info block\")\n\t\t\treturn err\n\t\t}\n\n\t\tif curBlock.BlockID != bl.PrevHeader.BlockId {\n\t\t\td.logger.WithFields(log.Fields{\"type\": consts.BlockError}).Error(\"info block compare with previous block\")\n\t\t\treturn fmt.Errorf(\"info block compare with previous block err curBlock: %d, PrevBlock: %d\", curBlock.BlockID, bl.PrevHeader.BlockId)\n\t\t}\n\n\t\tlastBlockID = bl.Header.BlockId\n\t\tlastBlockTime = bl.Header.Timestamp\n\n\t\tif err = bl.Check(); err != nil {\n\t\t\tvar replaceCount int64 = 1\n\t\t\tif err == block.ErrIncorrectRollbackHash {\n\t\t\t\treplaceCount++\n\t\t\t}\n\t\t\td.logger.WithFields(log.Fields{\"error\": err, \"from_host\": host,\n\t\t\t\t\"different\": fmt.Errorf(\"not match previous block %d, prev_position %d, current_position %d\",\n\t\t\t\t\tbl.PrevHeader.BlockId,\n\t\t\t\t\tbl.PrevHeader.NodePosition,\n\t\t\t\t\tbl.Header.NodePosition),\n\t\t\t\t\"type\": consts.BlockError, \"replaceCount\": replaceCount}).Error(\"checking block hash\")\n\t\t\t//if it is forked, replace the previous blocks to ones from the host\n\t\t\tif errReplace := ReplaceBlocksFromHost(ctx, host, bl.PrevHeader.BlockId, replaceCount); errReplace != nil {\n\t\t\t\treturn errReplace\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn bl.PlaySafe()\n\t}\n\n\tvar count int\n\tst := time.Now()\n\n\td.logger.WithFields(log.Fields{\"min_block\": curBlock.BlockID, \"max_block\": maxBlockID, \"count\": maxBlockID - curBlock.BlockID}).Info(\"starting downloading blocks\")\n\tfor blockID := curBlock.BlockID + 1; blockID <= maxBlockID; blockID += int64(network.BlocksPerRequest) {\n\t\tif loopErr := func() error {\n\t\t\tctxDone, cancel := context.WithCancel(ctx)\n\t\t\tdefer func() {\n\t\t\t\tcancel()\n\t\t\t\td.logger.WithFields(log.Fields{\"count\": count, \"time\": time.Since(st).String()}).Info(\"blocks downloaded\")\n\t\t\t}()\n\n\t\t\trawBlocksChan, err := tcpclient.GetBlocksBodies(ctxDone, host, blockID, false)\n\t\t\tif err != nil {\n\t\t\t\td.logger.WithFields(log.Fields{\"error\": err, \"type\": consts.BlockError}).Error(\"getting block body\")\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor rawBlock := range rawBlocksChan {\n\t\t\t\tif err = playRawBlock(rawBlock); err != nil {\n\t\t\t\t\t// d.logger.WithFields(log.Fields{\"error\": err, \"type\": consts.BlockError}).Error(\"playing raw block\")\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif candidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes)); err == nil && len(candidateNodes) > 0 {\n\t\t\t\t\tsyspar.SetRunModel(consts.CandidateNodeMode)\n\t\t\t\t} else {\n\t\t\t\t\tsyspar.SetRunModel(consts.HonorNodeMode)\n\t\t\t\t}\n\t\t\t\tcount++\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}(); loopErr != nil {\n\t\t\treturn loopErr\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc banNodePause(host string, blockID, blockTime int64, err error) {\n\tif err == nil || !utils.IsBanError(err) {\n\t\treturn\n\t}\n\n\treason := err.Error()\n\t//log.WithFields(log.Fields{\"host\": host, \"block_id\": blockID, \"block_time\": blockTime, \"err\": err}).Error(\"ban node\")\n\n\tn, err := syspar.GetNodeByHost(host)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"getting node by host\")\n\t\treturn\n\t}\n\n\terr = node.GetNodesBanService().RegisterBadBlock(n, blockID, blockTime, reason, false)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"node\": hex.EncodeToString(n.PublicKey),\n\t\t\t\"block\": blockID}).Error(\"registering bad block from node\")\n\t}\n}\n\n// GetHostWithMaxID returns host with maxBlockID\nfunc getHostWithMaxID(ctx context.Context, logger *log.Entry) (host string, maxBlockID int64, err error) {\n\tselectMode := SelectModel{}\n\thosts, err := selectMode.GetHostWithMaxID()\n\n\tif err != nil {\n\t\tlogger.WithError(err).Error(\"on filtering banned hosts\")\n\t}\n\n\thost, maxBlockID, err = tcpclient.HostWithMaxBlock(ctx, hosts)\n\tif len(hosts) == 0 || err == tcpclient.ErrNodesUnavailable {\n\t\thosts = conf.GetNodesAddr()\n\t\treturn tcpclient.HostWithMaxBlock(ctx, hosts)\n\t}\n\n\treturn\n}\n\n// ReplaceBlocksFromHost replaces blockchain received from the host.\n// Number (replaceCount) of blocks starting from blockID will be re-played.\nfunc ReplaceBlocksFromHost(ctx context.Context, host string, blockID, replaceCount int64) error {\n\tblocks, err := getBlocks(ctx, host, blockID, replaceCount)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttransaction.CleanCache()\n\n\t// mark all transaction as unverified\n\t_, err = sqldb.MarkVerifiedAndNotUsedTransactionsUnverified()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\n\t\t\t\"error\": err,\n\t\t\t\"type\":  consts.DBError,\n\t\t}).Error(\"marking verified and not used transactions unverified\")\n\t\treturn utils.ErrInfo(err)\n\t}\n\n\t// get starting blockID from slice of blocks\n\tif len(blocks) > 0 {\n\t\tblockID = blocks[len(blocks)-1].Header.BlockId\n\t}\n\n\t// we have the slice of blocks for applying\n\t// first of all we should rollback old blocks\n\tb := &sqldb.BlockChain{}\n\tmyRollbackBlocks, err := b.GetBlocksFrom(blockID-1, \"desc\", 0)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"getting rollback blocks from blockID\")\n\t\treturn utils.ErrInfo(err)\n\t}\n\tfor _, b := range myRollbackBlocks {\n\t\terr := rollback.RollbackBlock(b.Data)\n\t\tif err != nil {\n\t\t\treturn utils.ErrInfo(err)\n\t\t}\n\t}\n\n\tscript.SavepointSmartVMObjects()\n\terr = processBlocks(blocks)\n\tif err != nil {\n\t\tscript.RollbackSmartVMObjects()\n\t\treturn err\n\t}\n\tscript.ReleaseSmartVMObjects()\n\treturn err\n}\n\nfunc getBlocks(ctx context.Context, host string, blockID, minCount int64) ([]*block.Block, error) {\n\trollback := syspar.GetRbBlocks1()\n\tblocks := make([]*block.Block, 0)\n\tnextBlockID := blockID\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\t// load the block bodies from the host\n\tblocksCh, err := tcpclient.GetBlocksBodies(ctx, host, blockID, true)\n\tif err != nil {\n\t\treturn nil, utils.WithBan(errors.Wrapf(err, \"Getting bodies of blocks by id %d\", blockID))\n\t}\n\n\tfor binaryBlock := range blocksCh {\n\t\tif blockID < 2 {\n\t\t\tbreak\n\t\t}\n\n\t\t// if the limit of blocks received from the node was exaggerated\n\t\tif len(blocks) >= int(rollback) {\n\t\t\tbreak\n\t\t}\n\n\t\tbl, err := block.ProcessBlockByBinData(binaryBlock, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif bl.Header.BlockId != nextBlockID {\n\t\t\tlog.WithFields(log.Fields{\"header_block_id\": bl.Header.BlockId, \"block_id\": blockID, \"type\": consts.InvalidObject}).Error(\"block ids does not match\")\n\t\t\treturn nil, utils.WithBan(errors.New(\"bad block_data['block_id']\"))\n\t\t}\n\n\t\t// the public key of the one who has generated this block\n\t\tnodePublicKey, err := syspar.GetNodePublicKeyByPosition(bl.Header.NodePosition)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"header_block_id\": bl.Header.BlockId, \"block_id\": blockID, \"type\": consts.InvalidObject}).Error(\"block ids does not match\")\n\t\t\treturn nil, utils.ErrInfo(err)\n\t\t}\n\n\t\t// save the block\n\t\tblocks = append(blocks, bl)\n\n\t\t// check the signature\n\t\t_, okSignErr := utils.CheckSign([][]byte{nodePublicKey},\n\t\t\t[]byte(bl.ForSign()),\n\t\t\tbl.Header.Sign, true)\n\t\tif okSignErr == nil && len(blocks) >= int(minCount) {\n\t\t\tbreak\n\t\t}\n\n\t\tnextBlockID--\n\t}\n\n\treturn blocks, nil\n}\n\nfunc processBlocks(blocks []*block.Block) error {\n\t// go through new blocks from the smallest block_id to the largest block_id\n\tprevBlocks := make(map[int64]*block.Block, 0)\n\tfor i := len(blocks) - 1; i >= 0; i-- {\n\t\tb := blocks[i]\n\t\tif _, ok := prevBlocks[b.Header.BlockId-1]; ok {\n\t\t\tb.PrevHeader = prevBlocks[b.Header.BlockId-1].Header\n\t\t}\n\t\tif err := b.Check(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := b.PlaySafe(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tprevBlocks[b.Header.BlockId] = b\n\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/daemons/candidate_node_votings.go",
    "content": "package daemons\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype VotingRes struct {\n\tVoteMsgInfo network.VoteMsg `json:\"voteMsgInfo\"`\n\tErr         string          `json:\"err\"`\n}\n\ntype VotingTotal struct {\n\tData          map[string]VotingRes `json:\"data\"`\n\tAgreeQuantity int64                `json:\"agreeQuantity\"`\n\tLocalAddress  string               `json:\"localAddress\"`\n\tSt            int64                `json:\"st\"`\n}\n\nfunc ToUpdateMachineStatus(currentTcpAddress, tcpAddress string, ch chan map[string]VotingRes, logger *log.Entry) error {\n\tdata, err := tcpclient.UpdateMachineStatus(currentTcpAddress, tcpAddress, logger)\n\tvoteMsg := &network.VoteMsg{}\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending request error\")\n\t\tvoteMsg.Msg = \"tcp connection error\"\n\t\tvoteMsg.LocalAddress = currentTcpAddress\n\t\tvoteMsg.TcpAddress = tcpAddress\n\t\tvoteMsg.Time = time.Now().UnixMilli()\n\t\tch <- map[string]VotingRes{\n\t\t\ttcpAddress: {*voteMsg, voteMsg.Msg},\n\t\t}\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(data, &voteMsg)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError}).Error(\"JSONUnmarshallError\")\n\t\treturn err\n\t}\n\tch <- map[string]VotingRes{\n\t\ttcpAddress: {*voteMsg, \"\"},\n\t}\n\treturn nil\n}\n\nfunc ToBroadcastNodeConnInfo(votingTotal VotingTotal, tcpAddress string, logger *log.Entry) error {\n\tdata, err := json.Marshal(votingTotal)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = tcpclient.BroadcastNodeConnInfo(tcpAddress, data, logger)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending request error\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc CandidateNodeVoting(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\tvar (\n\t\tcandidateNodes sqldb.CandidateNodes\n\t\terr            error\n\t\tagreeQuantity  int64\n\t\tst             int64\n\t)\n\tdefer func() {\n\t\td.sleepTime = time.Minute\n\t}()\n\tcandidateNodes, err = sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(candidateNodes) == 0 {\n\t\treturn nil\n\t}\n\t_, NodePublicKey := utils.GetNodeKeys()\n\tNodePublicKey = \"04\" + NodePublicKey\n\tvar (\n\t\tisHonorNode       bool\n\t\tcurrentTcpAddress string\n\t)\n\n\tfor _, node := range candidateNodes {\n\t\tif NodePublicKey == node.NodePubKey {\n\t\t\tisHonorNode = true\n\t\t\tcurrentTcpAddress = node.TcpAddress\n\t\t\tbreak\n\t\t}\n\t}\n\tif !isHonorNode {\n\t\treturn nil\n\t}\n\tch := make(chan map[string]VotingRes, len(candidateNodes))\n\tvar wg sync.WaitGroup\n\tfor _, node := range candidateNodes {\n\t\twg.Add(1)\n\t\tgo func(tcpAddress string) {\n\t\t\tdefer wg.Done()\n\t\t\terr = ToUpdateMachineStatus(currentTcpAddress, tcpAddress, ch, d.logger)\n\t\t\tif err != nil {\n\t\t\t\td.logger.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending voting request error\")\n\t\t\t}\n\t\t}(node.TcpAddress)\n\t}\n\twg.Wait()\n\n\tnodeConnMap := make(map[string]VotingRes, len(ch))\n\tfor i := 0; i < cap(ch); i++ {\n\t\tserverVotingInfo, ok := <-ch\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\t\tfor tcpAddress, res := range serverVotingInfo {\n\t\t\tif res.Err != \"\" {\n\t\t\t\tnodeConnMap[tcpAddress] = res\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\terr := checkServerSign(res.VoteMsgInfo)\n\t\t\tif err != nil {\n\t\t\t\tres.VoteMsgInfo.Msg = \"Signature verification failed\"\n\t\t\t\tres.VoteMsgInfo.Agree = false\n\t\t\t\td.logger.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sign error\")\n\t\t\t}\n\t\t\tif res.VoteMsgInfo.Agree {\n\t\t\t\tagreeQuantity++\n\t\t\t}\n\t\t\tnodeConnMap[tcpAddress] = res\n\t\t}\n\t}\n\tclose(ch)\n\tst = time.Now().UnixMilli()\n\tif len(nodeConnMap) > 0 {\n\t\tvar wg sync.WaitGroup\n\t\tfor _, node := range candidateNodes {\n\t\t\twg.Add(1)\n\t\t\tgo func(tcpAddress string) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tvotingTotal := VotingTotal{Data: nodeConnMap, AgreeQuantity: agreeQuantity, LocalAddress: currentTcpAddress, St: st}\n\t\t\t\terr = ToBroadcastNodeConnInfo(votingTotal, tcpAddress, d.logger)\n\t\t\t\tif err != nil {\n\t\t\t\t\td.logger.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"broadcast node conn info error\")\n\t\t\t\t}\n\t\t\t}(node.TcpAddress)\n\t\t}\n\t\twg.Wait()\n\t}\n\n\treturn nil\n}\n\nfunc checkServerSign(serverVoteMsg network.VoteMsg) error {\n\tcandidateNodeSql := &sqldb.CandidateNode{}\n\terr := candidateNodeSql.GetCandidateNodeByAddress(serverVoteMsg.TcpAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpk, err := hex.DecodeString(candidateNodeSql.NodePubKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpk = crypto.CutPub(pk)\n\t_, err = crypto.Verify(pk, []byte(serverVoteMsg.VerifyVoteForSign()), serverVoteMsg.Sign)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/daemons/common.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/statsd\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar (\n\t// MonitorDaemonCh is monitor daemon channel\n\tMonitorDaemonCh = make(chan []string, 100)\n\tNtpDriftFlag    = false\n)\n\ntype daemon struct {\n\tgoRoutineName string\n\tsleepTime     time.Duration\n\tlogger        *log.Entry\n\tatomic        uint32\n}\n\nvar daemonsList = map[string]func(context.Context, *daemon) error{\n\t\"BlocksCollection\":    BlocksCollection,\n\t\"BlockGenerator\":      BlockGenerator,\n\t\"Disseminator\":        Disseminator,\n\t\"QueueParserTx\":       QueueParserTx,\n\t\"QueueParserBlocks\":   QueueParserBlocks,\n\t\"Confirmations\":       Confirmations,\n\t\"Scheduler\":           Scheduler,\n\t\"CandidateNodeVoting\": CandidateNodeVoting,\n\t//\"ExternalNetwork\":   ExternalNetwork,\n}\n\nvar rollbackList = []string{\n\t\"BlocksCollection\",\n\t\"Confirmations\",\n}\n\nfunc daemonLoop(ctx context.Context, goRoutineName string, handler func(context.Context, *daemon) error, retCh chan string) {\n\tlogger := log.WithFields(log.Fields{\"daemon_name\": goRoutineName})\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.PanicRecoveredError, \"error\": r}).Error(\"panic in daemon\")\n\t\t\tpanic(r)\n\t\t}\n\t}()\n\n\terr := WaitDB(ctx)\n\tif err != nil {\n\t\treturn\n\t}\n\n\td := &daemon{\n\t\tgoRoutineName: goRoutineName,\n\t\tsleepTime:     100 * time.Millisecond,\n\t\tlogger:        logger,\n\t}\n\tidleDelay := time.NewTimer(d.sleepTime)\n\t//defer idleDelay.Stop()\n\tfor {\n\t\tidleDelay.Reset(d.sleepTime)\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tlogger.Info(\"daemon done his work\")\n\t\t\tretCh <- goRoutineName\n\t\t\treturn\n\t\tcase <-idleDelay.C:\n\t\t\tMonitorDaemonCh <- []string{d.goRoutineName, converter.Int64ToStr(time.Now().Unix())}\n\t\t\tstartTime := time.Now()\n\t\t\tcounterName := statsd.DaemonCounterName(goRoutineName)\n\t\t\thandler(ctx, d)\n\t\t\tstatsd.Client.TimingDuration(counterName+statsd.Time, time.Now().Sub(startTime), 1.0)\n\t\t}\n\t}\n}\n\n// StartDaemons starts daemons\nfunc StartDaemons(ctx context.Context, daemonsToStart []string) {\n\tgo WaitStopTime()\n\n\tdaemonsTable := make(map[string]string)\n\tgo func() {\n\t\tfor {\n\t\t\tdaemonNameAndTime := <-MonitorDaemonCh\n\t\t\tdaemonsTable[daemonNameAndTime[0]] = daemonNameAndTime[1]\n\t\t\tif time.Now().Unix()%10 == 0 {\n\t\t\t\tlog.Debugf(\"daemonsTable: %v\\n\", daemonsTable)\n\t\t\t}\n\t\t}\n\t}()\n\n\t//go Ntp_Work(ctx)\n\t// ctx, cancel := context.WithCancel(context.Background())\n\t// utils.CancelFunc = cancel\n\t// utils.ReturnCh = make(chan string)\n\n\tif conf.Config.TestRollBack {\n\t\tdaemonsToStart = rollbackList\n\t}\n\n\tlog.WithFields(log.Fields{\"daemons_to_start\": daemonsToStart}).Info(\"starting daemons\")\n\n\tfor _, name := range daemonsToStart {\n\t\thandler, ok := daemonsList[name]\n\t\tif ok {\n\t\t\tgo daemonLoop(ctx, name, handler, utils.ReturnCh)\n\t\t\tlog.WithFields(log.Fields{\"daemon_name\": name}).Info(\"started\")\n\t\t\tutils.DaemonsCount++\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.WithFields(log.Fields{\"daemon_name\": name}).Warning(\"unknown daemon name\")\n\t}\n}\n\nfunc getHostPort(h string) string {\n\tif strings.Contains(h, \":\") {\n\t\treturn h\n\t}\n\treturn fmt.Sprintf(\"%s:%d\", h, consts.DefaultTcpPort)\n}\n\n//ntp\nfunc Ntp_Work(ctx context.Context) {\n\tvar count = 0\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tlog.Error(\"Ntp_Work done his work\")\n\t\t\treturn\n\t\tcase <-time.After(time.Second * 4):\n\t\t\tb, err := utils.CheckClockDrift()\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"daemon_name Ntp_Work err\": err.Error()}).Error(\"Ntp_Work\")\n\t\t\t} else {\n\t\t\t\tif b {\n\t\t\t\t\tNtpDriftFlag = true\n\t\t\t\t\tcount = 0\n\t\t\t\t} else {\n\t\t\t\t\tcount++\n\t\t\t\t}\n\t\t\t\tif count > 10 {\n\t\t\t\t\tvar sp sqldb.PlatformParameter\n\t\t\t\t\tcount, err := sp.GetNumberOfHonorNodes()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.WithFields(log.Fields{\"Ntp_Work GetNumberOfHonorNodes  err\": err.Error()}).Error(\"GetNumberOfHonorNodes\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif NtpDriftFlag && count > 1 {\n\t\t\t\t\t\t\tNtpDriftFlag = false\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n}\n\nfunc generateProcessBlockNew(blockHeader, prevBlock *types.BlockHeader, trs [][]byte, classifyTxsMap map[int][]*transaction.Transaction) error {\n\tblockBin, err := generateNextBlock(blockHeader, prevBlock, trs)\n\tif err != nil {\n\t\treturn err\n\t}\n\t//err = block.InsertBlockWOForks(blockBin, true, false)\n\terr = block.InsertBlockWOForksNew(blockBin, classifyTxsMap, true, false)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on inserting new block\")\n\t\treturn err\n\t}\n\tlog.WithFields(log.Fields{\"block\": blockHeader.String(), \"type\": consts.SyncProcess}).Debug(\"Generated block ID\")\n\treturn nil\n}\n\nfunc GetRemoteGoodHosts() ([]string, error) {\n\tif syspar.IsHonorNodeMode() {\n\t\treturn node.GetNodesBanService().FilterBannedHosts(syspar.GetRemoteHosts())\n\t}\n\thosts := make([]string, 0)\n\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"getting candidate node list\")\n\t\treturn nil, err\n\t}\n\tfor _, node := range candidateNodes {\n\t\thosts = append(hosts, node.TcpAddress)\n\t}\n\treturn hosts, nil\n}\n"
  },
  {
    "path": "packages/daemons/confirmations.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar tick int\n\n// Confirmations gets and checks blocks from nodes\n// Getting amount of nodes, which has the same hash as we do\nfunc Confirmations(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\t// the first 2 minutes we sleep for 10 sec for blocks to be collected\n\ttick++\n\n\td.sleepTime = 1 * time.Second\n\tif tick < 12 {\n\t\td.sleepTime = 10 * time.Second\n\t}\n\n\tvar startBlockID int64\n\n\t// check last blocks, but not more than 5\n\tconfirmations := &sqldb.Confirmation{}\n\t_, err := confirmations.GetGoodBlock(consts.MinConfirmedNodes)\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting good block\")\n\t\treturn err\n\t}\n\n\tConfirmedBlockID := confirmations.BlockID\n\tinfoBlock := &sqldb.InfoBlock{}\n\t_, err = infoBlock.Get()\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting info block\")\n\t\treturn err\n\t}\n\tlastBlockID := infoBlock.BlockID\n\tif lastBlockID == 0 {\n\t\treturn nil\n\t}\n\n\tif lastBlockID-ConfirmedBlockID > 5 {\n\t\tstartBlockID = ConfirmedBlockID + 1\n\t\td.sleepTime = 10 * time.Second\n\t\ttick = 0 // reset the tick\n\t}\n\n\tif startBlockID == 0 {\n\t\tstartBlockID = lastBlockID\n\t}\n\n\treturn confirmationsBlocks(ctx, d, lastBlockID, startBlockID)\n}\n\nfunc confirmationsBlocks(ctx context.Context, d *daemon, lastBlockID, startBlockID int64) error {\n\tfor blockID := lastBlockID; blockID >= startBlockID; blockID-- {\n\t\tif err := ctx.Err(); err != nil {\n\t\t\td.logger.WithFields(log.Fields{\"type\": consts.ContextError, \"error\": err}).Error(\"error in context\")\n\t\t\treturn err\n\t\t}\n\n\t\tblock := sqldb.BlockChain{}\n\t\t_, err := block.Get(blockID)\n\t\tif err != nil {\n\t\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting block by ID\")\n\t\t\treturn err\n\t\t}\n\n\t\thashStr := string(converter.BinToHex(block.Hash))\n\t\td.logger.WithFields(log.Fields{\"hash\": hashStr}).Debug(\"checking hash\")\n\t\tif len(hashStr) == 0 {\n\t\t\td.logger.WithFields(log.Fields{\"hash\": hashStr, \"type\": consts.NotFound}).Debug(\"hash not found\")\n\t\t\tcontinue\n\t\t}\n\t\tvar hosts []string\n\t\thosts, err = GetRemoteGoodHosts()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tch := make(chan string)\n\t\tfor i := 0; i < len(hosts); i++ {\n\t\t\thost, err := tcpclient.NormalizeHostAddress(hosts[i], consts.DefaultTcpPort)\n\t\t\tif err != nil {\n\t\t\t\td.logger.WithFields(log.Fields{\"host\": hosts[i], \"type\": consts.ParseError, \"error\": err}).Error(\"wrong host address\")\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\td.logger.WithFields(log.Fields{\"host\": host, \"block_id\": blockID}).Debug(\"checking block id confirmed at node\")\n\t\t\tgo func() {\n\t\t\t\tIsReachable(host, blockID, ch, d.logger)\n\t\t\t}()\n\t\t}\n\t\tvar answer string\n\t\tvar st0, st1 int64\n\t\tfor i := 0; i < len(hosts); i++ {\n\t\t\tanswer = <-ch\n\t\t\tif answer == hashStr {\n\t\t\t\tst1++\n\t\t\t} else {\n\t\t\t\tst0++\n\t\t\t}\n\t\t}\n\t\tconfirmation := &sqldb.Confirmation{}\n\t\tconfirmation.GetConfirmation(blockID)\n\t\tconfirmation.BlockID = blockID\n\t\tconfirmation.Good = int32(st1)\n\t\tconfirmation.Bad = int32(st0)\n\t\tconfirmation.Time = time.Now().Unix()\n\t\tif err = confirmation.Save(); err != nil {\n\t\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"saving confirmation\")\n\t\t\treturn err\n\t\t}\n\n\t\tif blockID > startBlockID && st1 >= consts.MinConfirmedNodes {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// IsReachable checks if there is blockID on the host\nfunc IsReachable(host string, blockID int64, ch0 chan string, logger *log.Entry) {\n\tch := make(chan string, 1)\n\tgo func() {\n\t\tch <- tcpclient.CheckConfirmation(host, blockID, logger)\n\t}()\n\tselect {\n\tcase reachable := <-ch:\n\t\tch0 <- reachable\n\tcase <-time.After(consts.WaitConfirmedNodes * time.Second):\n\t\tch0 <- \"0\"\n\t}\n}\n"
  },
  {
    "path": "packages/daemons/disseminator.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Disseminator is send to all nodes from nodes_connections the following data\n// if we are honor node: sends blocks and transactions hashes\n// else send the full transactions\nfunc Disseminator(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\tDBLock()\n\tdefer DBUnlock()\n\n\tvar (\n\t\tisHonorNode = true\n\t\tselectMode  = SelectModel{}\n\t)\n\tmyNodePosition, err := selectMode.GetThisNodePosition()\n\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"finding node\")\n\t\tisHonorNode = false\n\t}\n\n\tif isHonorNode {\n\t\t// send blocks and transactions hashes\n\t\td.logger.Debug(\"we are honor_node, sending hashes\")\n\t\treturn sendBlockWithTxHashes(ctx, myNodePosition, d.logger)\n\t}\n\n\t// we are not honor node for this StateID and WalletID, so just send transactions\n\td.logger.Debug(\"we are honor_node, sending transactions\")\n\treturn sendTransactions(ctx, d.logger)\n}\n\nfunc sendTransactions(ctx context.Context, logger *log.Entry) error {\n\t// get unsent transactions\n\ttrs, err := sqldb.GetAllUnsentTransactions(syspar.GetMaxTxCount())\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all unsent transactions\")\n\t\treturn err\n\t}\n\n\tif trs == nil || len(*trs) == 0 {\n\t\tlogger.Info(\"transactions not found\")\n\t\treturn nil\n\t}\n\n\thosts := make([]string, 0)\n\tif syspar.IsHonorNodeMode() {\n\t\thosts = syspar.GetDefaultRemoteHosts()\n\t} else {\n\t\tcandidateNodes, err := GetCandidateNodes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, node := range candidateNodes {\n\t\t\thosts = append(hosts, node.TcpAddress)\n\t\t}\n\t}\n\n\tif err := tcpclient.SendTransacitionsToAll(ctx, hosts, *trs); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"on sending transactions\")\n\t\treturn err\n\t}\n\n\tif len(hosts) > 0 {\n\t\t// set all transactions as sent\n\t\tvar hashArr [][]byte\n\t\tfor _, tr := range *trs {\n\t\t\thashArr = append(hashArr, tr.Hash)\n\t\t}\n\t\tif err := sqldb.MarkTransactionSentBatches(hashArr); err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"marking transaction sent\")\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// send block and transactions hashes\nfunc sendBlockWithTxHashes(ctx context.Context, honorNodeID int64, logger *log.Entry) error {\n\tblock, err := sqldb.BlockGetUnsent()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting unsent blocks\")\n\t\treturn err\n\t}\n\n\ttrs, err := sqldb.GetAllUnsentTransactions(syspar.GetMaxTxCount())\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting unsent transactions\")\n\t\treturn err\n\t}\n\n\tif (trs == nil || len(*trs) == 0) && block == nil {\n\t\t// it's nothing to send\n\t\tlogger.Debug(\"nothing to send\")\n\t\treturn nil\n\t}\n\tselectModel := SelectModel{}.GetWorkMode()\n\t_, ok := selectModel.(*HonorNodeMode)\n\tvar (\n\t\thosts          []string\n\t\tbanHosts       []string\n\t\tcandidateNodes sqldb.CandidateNodes\n\t)\n\tif ok {\n\t\thosts, banHosts, err = node.GetNodesBanService().FilterHosts(syspar.GetRemoteHosts())\n\t} else {\n\t\tcandidateNodes, err = GetCandidateNodes()\n\t\tfor _, node := range candidateNodes {\n\t\t\thosts = append(hosts, node.TcpAddress)\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on getting remotes hosts\")\n\t\treturn err\n\t}\n\tif len(banHosts) > 0 {\n\t\tif err := tcpclient.SendFullBlockToAll(ctx, banHosts, nil, *trs, honorNodeID); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.TCPClientError, \"error\": err}).Warn(\"on sending block with hashes to ban hosts\")\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := tcpclient.SendFullBlockToAll(ctx, hosts, block, *trs, honorNodeID); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.TCPClientError, \"error\": err}).Warn(\"on sending block with hashes to all\")\n\t\treturn err\n\t}\n\n\t// mark all transactions and block as sent\n\tif block != nil {\n\t\terr = block.MarkSent()\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"marking block sent\")\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif trs != nil {\n\t\tvar hashArr [][]byte\n\t\tfor _, tr := range *trs {\n\t\t\thashArr = append(hashArr, tr.Hash)\n\t\t}\n\t\tif err := sqldb.MarkTransactionSentBatches(hashArr); err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"marking transaction sent\")\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/daemons/external_network.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/api\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\terrExternalNone    = iota // 0 - no error\n\terrExternalTx             // 1 - tx error\n\terrExternalAttempt        // 2 - attempt error\n\terrExternalTimeout        // 3 - timeout of getting txstatus\n\n\tmaxAttempts           = 10\n\tstatusTimeout         = 60\n\texternalDeamonTimeout = 2\n\tapiExt                = `/api/v2/`\n)\n\nvar (\n\tnodePrivateKey []byte\n\tnodeKeyID      int64\n\tnodePublicKey  string\n\tauthNet        = map[string]string{}\n)\n\nfunc loginNetwork(urlPath string) (connect *api.Connect, err error) {\n\tif len(nodePrivateKey) == 0 {\n\t\tvar pubKey []byte\n\t\tnodePrivateKey = syspar.GetNodePrivKey()\n\t\tif pubKey, err = crypto.PrivateToPublic(nodePrivateKey); err != nil {\n\t\t\treturn\n\t\t}\n\t\tnodeKeyID = crypto.Address(pubKey)\n\t\tnodePublicKey = crypto.PubToHex(pubKey)\n\t}\n\tconnect = &api.Connect{\n\t\tAuth:       authNet[urlPath],\n\t\tPrivateKey: nodePrivateKey,\n\t\tPublicKey:  nodePublicKey,\n\t\tRoot:       urlPath,\n\t}\n\tif err = connect.Login(); err != nil {\n\t\tauthNet[urlPath] = connect.Auth\n\t}\n\treturn\n}\n\nfunc SendExternalTransaction() error {\n\tvar (\n\t\terr     error\n\t\tconnect *api.Connect\n\t\tdelList []int64\n\t\thash    string\n\t)\n\n\ttoWait := map[string][]sqldb.ExternalBlockchain{}\n\tincAttempt := func(id int64) {\n\t\tif err = sqldb.IncExternalAttempt(id); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"IncAttempt\")\n\t\t}\n\t}\n\tsendResult := func(item sqldb.ExternalBlockchain, block, errCode int64, resText string) {\n\t\tdefer func() {\n\t\t\tdelList = append(delList, item.Id)\n\t\t}()\n\t\tif len(item.ResultContract) == 0 {\n\t\t\treturn\n\t\t}\n\t\tif err := transaction.CreateContract(item.ResultContract, nodeKeyID,\n\t\t\tmap[string]any{\n\t\t\t\t\"Status\": errCode,\n\t\t\t\t\"Msg\":    resText,\n\t\t\t\t\"Block\":  block,\n\t\t\t\t\"UID\":    item.Uid,\n\t\t\t}, nodePrivateKey); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ContractError, \"err\": err}).Error(\"CreateContract\")\n\t\t}\n\t}\n\tlist, err := sqldb.GetExternalList()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"GetExternalList\")\n\t\treturn err\n\t}\n\ttimeOut := time.Now().Unix() - 10*(syspar.GetGapsBetweenBlocks()+\n\t\tsyspar.GetMaxBlockGenerationTime()/1000)\n\tfor _, item := range list {\n\t\troot := item.Url + apiExt\n\t\tif item.Sent == 0 {\n\t\t\tif timeOut > item.TxTime {\n\t\t\t\tdelList = append(delList, item.Id)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif connect, err = loginNetwork(root); err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.AccessDenied, \"error\": err}).Error(\"loginNetwork\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tvalues := url.Values{\"UID\": {item.Uid}}\n\n\t\t\tvar params map[string]any\n\t\t\tif err = json.Unmarshal([]byte(item.Value), &params); err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"Unmarshal params\")\n\t\t\t\tdelList = append(delList, item.Id)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor key, val := range params {\n\t\t\t\tvalues[key] = []string{fmt.Sprint(val)}\n\t\t\t}\n\t\t\tvalues[\"nowait\"] = []string{\"1\"}\n\t\t\tvalues[\"txtime\"] = []string{converter.Int64ToStr(item.TxTime)}\n\t\t\t_, hash, err = connect.PostTxResult(item.ExternalContract, &values)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"PostContract\")\n\t\t\t\tif item.Attempts >= maxAttempts-1 {\n\t\t\t\t\tsendResult(item, 0, errExternalAttempt, ``)\n\t\t\t\t} else {\n\t\t\t\t\tincAttempt(item.Id)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlog.WithFields(log.Fields{\"hash\": hash, \"txtime\": values[\"txtime\"][0],\n\t\t\t\t\t\"nodeKey\": converter.Int64ToStr(nodeKeyID)}).Info(\"SendExternalTransaction\")\n\t\t\t\tbHash, err := hex.DecodeString(hash)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"error\": err}).Error(\"DecodeHex\")\n\t\t\t\t\tincAttempt(item.Id)\n\t\t\t\t} else if err = sqldb.HashExternalTx(item.Id, bHash); err != nil {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"HashExternal\")\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\ttoWait[item.Url] = append(toWait[item.Url], item)\n\t\t}\n\t}\n\tfor _, waitList := range toWait {\n\t\tif connect, err = loginNetwork(waitList[0].Url + apiExt); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.AccessDenied, \"error\": err}).Error(\"loginNetwork\")\n\t\t\tcontinue\n\t\t}\n\t\tvar hashes []string\n\t\tfor _, item := range waitList {\n\t\t\thashes = append(hashes, hex.EncodeToString(item.Hash))\n\t\t}\n\t\tresults, err := connect.WaitTxList(hashes)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"WaitTxList\")\n\t\t\tcontinue\n\t\t}\n\t\ttimeOut = time.Now().Unix() - statusTimeout\n\t\tfor _, item := range waitList {\n\t\t\tif result, ok := results[hex.EncodeToString(item.Hash)]; ok {\n\t\t\t\terrCode := int64(errExternalNone)\n\t\t\t\tif result.BlockID == 0 {\n\t\t\t\t\terrCode = errExternalTx\n\t\t\t\t}\n\t\t\t\tsendResult(item, result.BlockID, errCode, result.Msg)\n\t\t\t} else if timeOut > item.TxTime {\n\t\t\t\tsendResult(item, 0, errExternalTimeout, ``)\n\t\t\t}\n\t\t}\n\t}\n\tif len(delList) > 0 {\n\t\tif err = sqldb.DelExternalList(delList); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ExternalNetwork sends txinfo to the external network\nfunc ExternalNetwork(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\td.sleepTime = externalDeamonTimeout * time.Second\n\treturn SendExternalTransaction()\n}\n"
  },
  {
    "path": "packages/daemons/genesis.go",
    "content": "package daemons\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc InitialLoad(logger *log.Entry) error {\n\n\t// check for initial load\n\ttoLoad, err := needLoad(logger)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif toLoad {\n\t\tlogger.Debug(\"start first block loading\")\n\n\t\tif err := firstLoad(logger); err != nil {\n\t\t\tlogger.WithError(err).Error(\"cant load first block form file or host\")\n\t\t\treturn err\n\t\t}\n\n\t\tif err := sqldb.UpdateSchema(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// init first block from file or from embedded value\nfunc loadFirstBlock(logger *log.Entry) error {\n\tnewBlock, err := os.ReadFile(conf.Config.DirPathConf.FirstBlockPath)\n\tif err != nil && len(conf.Config.BootNodes.NodesAddr) == 0 {\n\t\treturn errors.Wrap(err, \"reading first block from file path\")\n\t}\n\tif len(conf.Config.BootNodes.NodesAddr) > 0 {\n\t\tctxDone, cancel := context.WithCancel(context.Background())\n\t\tdefer func() {\n\t\t\tcancel()\n\t\t}()\n\t\thost, _, err := getHostWithMaxID(ctxDone, logger)\n\t\tif err != nil {\n\t\t\treturn errors.Wrap(err, \"reading host\")\n\t\t}\n\t\trawBlocksChan, err := tcpclient.GetBlocksBodies(ctxDone, host, 1, true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor rawBlock := range rawBlocksChan {\n\t\t\tnewBlock = rawBlock\n\t\t}\n\t}\n\tif err = block.InsertBlockWOForksNew(newBlock, nil, false, true); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ParserError, \"error\": err}).Error(\"inserting new block\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc firstLoad(logger *log.Entry) error {\n\tDBLock()\n\tdefer DBUnlock()\n\n\treturn loadFirstBlock(logger)\n}\n\nfunc needLoad(logger *log.Entry) (bool, error) {\n\tinfoBlock := &sqldb.InfoBlock{}\n\t_, err := infoBlock.Get()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"getting info block\")\n\t\treturn false, err\n\t}\n\t// we have empty blockchain, we need to load blockchain from file or other source\n\tif infoBlock.BlockID == 0 {\n\t\tlogger.Debug(\"blockchain should be loaded\")\n\t\treturn true, nil\n\t}\n\treturn false, nil\n}\n"
  },
  {
    "path": "packages/daemons/locking.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar mutex = sync.Mutex{}\n\n// WaitDB waits for the end of the installation\nfunc WaitDB(ctx context.Context) error {\n\t// There is could be the situation when installation is not over yet.\n\t// Database could be created but tables are not inserted yet\n\n\tif sqldb.DBConn != nil && CheckDB() {\n\t\treturn nil\n\t}\n\n\t// poll a base with period\n\ttick := time.NewTicker(1 * time.Second)\n\tfor {\n\t\tselect {\n\t\tcase <-tick.C:\n\t\t\tif sqldb.DBConn != nil && CheckDB() {\n\t\t\t\treturn nil\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n}\n\n// CheckDB check if installation complete or not\nfunc CheckDB() bool {\n\tinstall := &sqldb.Install{}\n\n\terr := install.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting install\")\n\t}\n\n\tif install.Progress == sqldb.ProgressComplete {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// DBLock locks daemons\nfunc DBLock() {\n\tmutex.Lock()\n}\n\n// DBUnlock unlocks database\nfunc DBUnlock() {\n\ttransaction.CleanCache()\n\tmutex.Unlock()\n}\n"
  },
  {
    "path": "packages/daemons/mode.go",
    "content": "package daemons\n\nimport (\n\t\"encoding/hex\"\n\t\"errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype Model interface {\n\tGetThisNodePosition() (int64, error)\n\tGetHostWithMaxID() (hosts []string, err error)\n}\n\ntype HonorNodeMode struct {\n}\n\nfunc (honorNodeMode *HonorNodeMode) GetThisNodePosition() (int64, error) {\n\treturn syspar.GetNodePositionByPublicKey(syspar.GetNodePubKey())\n}\nfunc (honorNodeMode *HonorNodeMode) GetHostWithMaxID() ([]string, error) {\n\tnbs := node.GetNodesBanService()\n\thosts, err := nbs.FilterBannedHosts(syspar.GetRemoteHosts())\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on filtering banned hosts\")\n\t\treturn nil, err\n\t}\n\treturn hosts, nil\n}\n\ntype CandidateNodeMode struct {\n}\n\nfunc (candidateNodeMode *CandidateNodeMode) GetThisNodePosition() (int64, error) {\n\treturn GetCandidateNodePositionByPublicKey()\n}\nfunc (candidateNodeMode *CandidateNodeMode) GetHostWithMaxID() ([]string, error) {\n\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"getting candidate node list\")\n\t\treturn nil, err\n\t}\n\thosts := make([]string, len(candidateNodes))\n\tfor index, node := range candidateNodes {\n\t\thosts[index] = node.TcpAddress\n\t}\n\n\treturn hosts, nil\n}\n\ntype SelectModel struct {\n}\n\nfunc (s *SelectModel) GetThisNodePosition() (int64, error) {\n\treturn s.GetWorkMode().GetThisNodePosition()\n}\nfunc (s *SelectModel) GetHostWithMaxID() ([]string, error) {\n\treturn s.GetWorkMode().GetHostWithMaxID()\n}\n\nfunc (s SelectModel) GetWorkMode() Model {\n\tif syspar.IsHonorNodeMode() {\n\t\treturn &HonorNodeMode{} //1\n\t}\n\treturn &CandidateNodeMode{} //2\n}\n\nfunc GetCandidateNodePositionByPublicKey() (int64, error) {\n\tNodePublicKey := hex.EncodeToString(syspar.GetNodePubKey())\n\tif len(NodePublicKey) < 1 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node public key is empty\")\n\t\treturn 0, errors.New(`node public key is empty`)\n\t}\n\tcandidateNode := &sqldb.CandidateNode{}\n\n\tif candidateNode.GetCandidateNodeByPublicKey(NodePublicKey) != nil {\n\t\tlog.WithFields(log.Fields{\"error\": candidateNode.GetCandidateNodeByPublicKey(NodePublicKey)}).Error(\"getting candidate node error\")\n\t\treturn 0, candidateNode.GetCandidateNodeByPublicKey(NodePublicKey)\n\t}\n\n\treturn candidateNode.ID, nil\n}\nfunc GetCandidateNodes() (sqldb.CandidateNodes, error) {\n\tnodePublicKey := hex.EncodeToString(syspar.GetNodePubKey())\n\tif len(nodePublicKey) < 1 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node public key is empty\")\n\t\treturn nil, errors.New(`node public key is empty`)\n\t}\n\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"getting candidate node error\")\n\t\treturn nil, err\n\t}\n\tret := make(sqldb.CandidateNodes, 0)\n\tfor _, node := range candidateNodes {\n\t\tif \"04\"+nodePublicKey != node.NodePubKey {\n\t\t\tret = append(ret, node)\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "packages/daemons/monitoring.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Monitoring starts monitoring\nfunc Monitoring(w http.ResponseWriter, r *http.Request) {\n\tvar buf bytes.Buffer\n\n\tinfoBlock := &sqldb.InfoBlock{}\n\t_, err := infoBlock.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting info block\")\n\t\tlogError(w, fmt.Errorf(\"can't get info block: %s\", err))\n\t\treturn\n\t}\n\taddKey(&buf, \"info_block_id\", infoBlock.BlockID)\n\taddKey(&buf, \"info_block_hash\", converter.BinToHex(infoBlock.Hash))\n\taddKey(&buf, \"info_block_time\", infoBlock.Time)\n\taddKey(&buf, \"info_block_key_id\", infoBlock.KeyID)\n\taddKey(&buf, \"info_block_ecosystem_id\", infoBlock.EcosystemID)\n\taddKey(&buf, \"info_block_node_position\", infoBlock.NodePosition)\n\taddKey(&buf, \"honor_nodes_count\", syspar.GetNumberOfNodes())\n\n\tblock := &sqldb.BlockChain{}\n\t_, err = block.GetMaxBlock()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting max block\")\n\t\tlogError(w, fmt.Errorf(\"can't get max block: %s\", err))\n\t\treturn\n\t}\n\taddKey(&buf, \"last_block_id\", block.ID)\n\taddKey(&buf, \"last_block_hash\", converter.BinToHex(block.Hash))\n\taddKey(&buf, \"last_block_time\", block.Time)\n\taddKey(&buf, \"last_block_wallet\", block.KeyID)\n\taddKey(&buf, \"last_block_state\", block)\n\taddKey(&buf, \"last_block_transactions\", block.Tx)\n\n\ttrCount, err := sqldb.GetTransactionCountAll()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting transaction count all\")\n\t\tlogError(w, fmt.Errorf(\"can't get transactions count: %s\", err))\n\t\treturn\n\t}\n\taddKey(&buf, \"transactions_count\", trCount)\n\n\tw.Write(buf.Bytes())\n}\n\nfunc addKey(buf *bytes.Buffer, key string, value any) error {\n\tval, err := converter.InterfaceToStr(value)\n\tif err != nil {\n\t\treturn err\n\t}\n\tline := fmt.Sprintf(\"%s\\t%s\\n\", key, val)\n\tbuf.Write([]byte(line))\n\treturn nil\n}\n\nfunc logError(w http.ResponseWriter, err error) {\n\tw.Write([]byte(err.Error()))\n\treturn\n}\n"
  },
  {
    "path": "packages/daemons/queue_parser_blocks.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n/* Take the block from the queue. If this block has the bigger block id than the last block from our chain, then find the fork\n * If fork begins less then variables->rollback_blocks blocks ago, than\n *  - get the whole chain of blocks\n *  - roll back data from our blocks\n *  - insert the frontal data from a new chain\n *  - if there is no error, then roll back our data from the blocks\n *  - and insert new data\n *  - if there are errors, then roll back to the former data\n * */\n\n// QueueParserBlocks parses and applies blocks from the queue\nfunc QueueParserBlocks(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\tDBLock()\n\tdefer DBUnlock()\n\n\tinfoBlock := &sqldb.InfoBlock{}\n\t_, err := infoBlock.Get()\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting info block\")\n\t\treturn err\n\t}\n\tqueueBlock := &sqldb.QueueBlock{}\n\t_, err = queueBlock.Get()\n\tif err != nil {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting queue block\")\n\t\treturn err\n\t}\n\tif len(queueBlock.Hash) == 0 {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"queue block not found\")\n\t\treturn err\n\t}\n\n\t// check if the block gets in the rollback_blocks_1 limit\n\tif queueBlock.BlockID > infoBlock.BlockID+syspar.GetRbBlocks1() {\n\t\tqueueBlock.DeleteOldBlocks()\n\t\treturn utils.ErrInfo(\"rollback_blocks_1\")\n\t}\n\n\t// is it old block in queue ?\n\tif queueBlock.BlockID <= infoBlock.BlockID {\n\t\tqueueBlock.DeleteOldBlocks()\n\t\treturn utils.ErrInfo(fmt.Errorf(\"old block %d <= %d\", queueBlock.BlockID, infoBlock.BlockID))\n\t}\n\n\tif queueBlock.HonorNodeID == conf.Config.KeyID {\n\t\td.logger.WithFields(log.Fields{\"type\": consts.DuplicateObject}).Debug(\"queueBlock generated by myself\", queueBlock.BlockID)\n\t\treturn utils.ErrInfo(fmt.Errorf(\"queueBlock generated by myself: %d\", queueBlock.BlockID))\n\t}\n\n\tnodeHost, err := syspar.GetNodeHostByPosition(queueBlock.HonorNodeID)\n\tif err != nil {\n\t\tqueueBlock.DeleteQueueBlockByHash()\n\t\treturn utils.ErrInfo(err)\n\t}\n\tblockID := queueBlock.BlockID\n\n\thost := utils.GetHostPort(nodeHost)\n\t// update our chain till maxBlockID from the host\n\treturn UpdateChain(ctx, d, host, blockID)\n}\n"
  },
  {
    "path": "packages/daemons/queue_parser_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n)\n\n// QueueParserTx parses transaction from the queue\nfunc QueueParserTx(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\tDBLock()\n\tdefer DBUnlock()\n\t//\n\t//infoBlock := &sqldb.InfoBlock{}\n\t//_, err := infoBlock.Get()\n\t//if err != nil {\n\t//\td.logger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting info block\")\n\t//\treturn err\n\t//}\n\t//if infoBlock.BlockId == 0 {\n\t//\td.logger.Debug(\"no blocks for parsing\")\n\t//\treturn nil\n\t//}\n\n\terr := transaction.ProcessTransactionsQueue(nil)\n\tif err != nil {\n\t\td.logger.WithError(err).Error(\"parsing transactions\")\n\t\treturn err\n\t}\n\t//for {\n\t//\tselect {\n\t//\tcase attempt := <-transaction.ChanTxAttempt:\n\t//\t\tif attempt {\n\t//\t\t\terr = transaction.ProcessTransactionsAttempt(p.DbTransaction)\n\t//\t\t\tif err != nil {\n\t//\t\t\t\td.logger.WithError(err).Error(\"parsing transactions attempt\")\n\t//\t\t\t\treturn err\n\t//\t\t\t}\n\t//\t\t}\n\t//\tdefault:\n\t//\t\treturn nil\n\t//\t}\n\t//}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/daemons/scheduler.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/scheduler\"\n\t\"github.com/IBAX-io/go-ibax/packages/scheduler/contract\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc loadContractTasks() error {\n\tstateIDs, _, err := sqldb.GetAllSystemStatesIDs()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"get all system states ids\")\n\t\treturn err\n\t}\n\n\tfor _, stateID := range stateIDs {\n\t\tif !sqldb.NewDbTransaction(nil).IsTable(fmt.Sprintf(\"%d_cron\", stateID)) {\n\t\t\treturn nil\n\t\t}\n\n\t\tc := sqldb.Cron{}\n\t\tc.SetTablePrefix(fmt.Sprintf(\"%d\", stateID))\n\t\ttasks, err := c.GetAllCronTasks()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"get all cron tasks\")\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, cronTask := range tasks {\n\t\t\terr = scheduler.UpdateTask(&scheduler.Task{\n\t\t\t\tID:       cronTask.UID(),\n\t\t\t\tCronSpec: cronTask.Cron,\n\t\t\t\tHandler: &contract.ContractHandler{\n\t\t\t\t\tContract: cronTask.Contract,\n\t\t\t\t},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Scheduler starts contracts on schedule\nfunc Scheduler(ctx context.Context, d *daemon) error {\n\tif atomic.CompareAndSwapUint32(&d.atomic, 0, 1) {\n\t\tdefer atomic.StoreUint32(&d.atomic, 0)\n\t} else {\n\t\treturn nil\n\t}\n\td.sleepTime = time.Hour\n\treturn loadContractTasks()\n}\n"
  },
  {
    "path": "packages/daemons/stopdaemons.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/chain/system\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// WaitStopTime closes the database and stop daemons\nfunc WaitStopTime() {\n\tvar first bool\n\tfor {\n\t\tif sqldb.DBConn == nil {\n\t\t\ttime.Sleep(time.Second * 3)\n\t\t\tcontinue\n\t\t}\n\t\tif !first {\n\t\t\terr := sqldb.NewDbTransaction(nil).Delete(\"stop_daemons\", \"\")\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting from stop daemons\")\n\t\t\t}\n\t\t\tfirst = true\n\t\t}\n\t\tdExists, err := sqldb.NewDbTransaction(nil).Single(`SELECT stop_time FROM stop_daemons`).Int64()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting stop_time from StopDaemons\")\n\t\t}\n\t\tif dExists > 0 {\n\t\t\tutils.CancelFunc()\n\t\t\tfor i := 0; i < utils.DaemonsCount; i++ {\n\t\t\t\tname := <-utils.ReturnCh\n\t\t\t\tlog.WithFields(log.Fields{\"daemon_name\": name}).Debug(\"daemon stopped\")\n\t\t\t}\n\n\t\t\terr := sqldb.GormClose()\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"gorm close\")\n\t\t\t}\n\t\t\terr = system.RemovePidFile()\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\t\"type\": consts.IOError, \"error\": err,\n\t\t\t\t}).Error(\"removing pid file\")\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t\ttime.Sleep(time.Second)\n\t}\n}\n"
  },
  {
    "path": "packages/daemons/upd_full_nodes.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n"
  },
  {
    "path": "packages/daemons/wait_for_signals.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage daemons\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/chain/system\"\n\t\"github.com/IBAX-io/go-ibax/packages/statsd\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n/*\n#include <stdio.h>\n#include <signal.h>\n\nextern void go_callback_int();\nstatic inline void SigBreak_Handler(int n_signal){\n    printf(\"closed\\n\");\n\tgo_callback_int();\n}\nstatic inline void waitSig() {\n    #if (WIN32 || WIN64)\n    signal(SIGBREAK, &SigBreak_Handler);\n    signal(SIGINT, &SigBreak_Handler);\n    #endif\n}\n*/\nimport (\n\t\"C\"\n)\n\n//export go_callback_int\nfunc go_callback_int() {\n\tSigChan <- syscall.Signal(1)\n}\n\n// SigChan is a channel\nvar SigChan chan os.Signal\n\nfunc waitSig() {\n\tC.waitSig()\n}\n\n// WaitForSignals waits for Interrupt os.Kill signals\nfunc WaitForSignals() {\n\tSigChan = make(chan os.Signal, 1)\n\twaitSig()\n\tgo func() {\n\t\tsignal.Notify(SigChan, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGQUIT)\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-SigChan:\n\t\t\t\tif utils.CancelFunc != nil {\n\t\t\t\t\tutils.CancelFunc()\n\t\t\t\t\tfor i := 0; i < utils.DaemonsCount; i++ {\n\t\t\t\t\t\tname := <-utils.ReturnCh\n\t\t\t\t\t\tlog.WithFields(log.Fields{\"daemon_name\": name}).Debug(\"daemon stopped\")\n\t\t\t\t\t}\n\n\t\t\t\t\tlog.Debug(\"Daemons killed\")\n\t\t\t\t}\n\n\t\t\t\tif sqldb.DBConn != nil {\n\t\t\t\t\terr := sqldb.GormClose()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"closing gorm\")\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\terr := system.RemovePidFile()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\t\t\"type\": consts.IOError, \"error\": err, \"path\": conf.Config.GetPidPath(),\n\t\t\t\t\t}).Error(\"removing file\")\n\t\t\t\t}\n\t\t\t\tstatsd.Close()\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "packages/language/language.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage language\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"unicode/utf8\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n//cacheLang is cache for language, first level is lang_name, second is lang dictionary\ntype cacheLang struct {\n\tres map[string]*map[string]string\n}\n\nvar (\n\t// LangList is the list of available languages. It stores two-bytes codes\n\tLangList []string\n\tlang     = make(map[int]*cacheLang)\n\tmutex    = &sync.RWMutex{}\n)\n\n// IsLang checks if there is a language with code name\nfunc IsLang(code string) bool {\n\tif LangList == nil {\n\t\treturn true\n\t}\n\tfor _, val := range LangList {\n\t\tif val == code {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// DefLang returns the default language\nfunc DefLang() string {\n\tif LangList == nil {\n\t\treturn `en`\n\t}\n\treturn LangList[0]\n}\n\n// UpdateLang updates language sources for the specified state\nfunc UpdateLang(state int, name, value string) error {\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\tif _, ok := lang[state]; !ok {\n\t\tlang[state] = &cacheLang{make(map[string]*map[string]string)}\n\t}\n\tvar ires map[string]string\n\terr := json.Unmarshal([]byte(value), &ires)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"value\": value, \"error\": err}).Error(\"Unmarshalling json\")\n\t\treturn err\n\t}\n\tfor key, val := range ires {\n\t\tires[strings.ToLower(key)] = val\n\t}\n\tif len(ires) > 0 {\n\t\t(*lang[state]).res[name] = &ires\n\t}\n\treturn nil\n}\n\n// loadLang download the language sources from database for the state\nfunc loadLang(transaction *sqldb.DbTransaction, state int) error {\n\tlanguage := &sqldb.Language{}\n\tprefix := strconv.FormatInt(int64(state), 10)\n\n\tlanguages, err := language.GetAll(transaction, prefix)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Error querying all languages\")\n\t\treturn err\n\t}\n\tlist := make([]map[string]string, 0)\n\tfor _, l := range languages {\n\t\tlist = append(list, l.ToMap())\n\t}\n\tres := make(map[string]*map[string]string)\n\tfor _, ilist := range list {\n\t\tvar ires map[string]string\n\t\terr := json.Unmarshal([]byte(ilist[`res`]), &ires)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"value\": ilist[\"res\"], \"error\": err}).Error(\"Unmarshalling json\")\n\t\t}\n\t\tfor key, val := range ires {\n\t\t\tires[strings.ToLower(key)] = val\n\t\t}\n\t\tres[ilist[`name`]] = &ires\n\t}\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\tif _, ok := lang[state]; !ok {\n\t\tlang[state] = &cacheLang{}\n\t}\n\tlang[state].res = res\n\treturn nil\n}\n\n// LangText looks for the specified word through language sources and returns the meaning of the source\n// if it is found. Search goes according to the languages specified in 'accept'\nfunc LangText(transaction *sqldb.DbTransaction, in string, state int, accept string) (string, bool) {\n\tif strings.IndexByte(in, ' ') >= 0 || state == 0 {\n\t\treturn in, false\n\t}\n\tecosystem, name := converter.ParseName(in)\n\tif ecosystem != 0 {\n\t\tstate = int(ecosystem)\n\t\tin = name\n\t}\n\tif state == 0 {\n\t\treturn in, false\n\t}\n\tif _, ok := lang[state]; !ok {\n\t\tif err := loadLang(transaction, state); err != nil {\n\t\t\treturn err.Error(), false\n\t\t}\n\t}\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tlangs := strings.Split(accept, `,`)\n\tif _, ok := (*lang[state]).res[in]; !ok {\n\t\treturn in, false\n\t}\n\tif lres, ok := (*lang[state]).res[in]; ok {\n\t\tlng := DefLang()\n\t\tfor _, val := range langs {\n\t\t\tval = strings.ToLower(val)\n\t\t\tif len(val) < 2 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif !IsLang(val[:2]) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(val) >= 5 && val[2] == '-' {\n\t\t\t\tif _, ok := (*lres)[val[:5]]; ok {\n\t\t\t\t\tlng = val[:5]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif _, ok := (*lres)[val[:2]]; ok {\n\t\t\t\tlng = val[:2]\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif len((*lres)[lng]) == 0 {\n\t\t\tfor _, val := range *lres {\n\t\t\t\treturn val, true\n\t\t\t}\n\t\t}\n\t\treturn (*lres)[lng], true\n\t}\n\treturn in, false\n}\n\n// LangMacro replaces all inclusions of $resname$ in the incoming text with the corresponding language resources,\n// if they exist\nfunc LangMacro(input string, state int, accept string) string {\n\tif !strings.ContainsRune(input, '$') {\n\t\treturn input\n\t}\n\tsyschar := '$'\n\tlength := utf8.RuneCountInString(input)\n\tresult := make([]rune, 0, length)\n\tisName := false\n\tname := make([]rune, 0, 128)\n\tclearname := func() {\n\t\tresult = append(append(result, syschar), name...)\n\t\tisName = false\n\t\tname = name[:0]\n\t}\n\tfor _, r := range input {\n\t\tif r != syschar {\n\t\t\tif isName {\n\t\t\t\tname = append(name, r)\n\t\t\t\tif len(name) > 64 || r < ' ' {\n\t\t\t\t\tclearname()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult = append(result, r)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif isName {\n\t\t\tvalue, ok := LangText(nil, string(name), state, accept)\n\t\t\tif ok {\n\t\t\t\tresult = append(result, []rune(value)...)\n\t\t\t\tisName = false\n\t\t\t} else {\n\t\t\t\tresult = append(append(result, syschar), name...)\n\t\t\t}\n\t\t\tname = name[:0]\n\t\t} else {\n\t\t\tisName = true\n\t\t}\n\t}\n\tif isName {\n\t\tresult = append(append(result, syschar), name...)\n\t}\n\n\treturn string(result)\n}\n\n// GetLang returns the first language from accept-language\nfunc GetLang(state int, accept string) (lng string) {\n\tlng = DefLang()\n\tfor _, val := range strings.Split(accept, `,`) {\n\t\tif len(val) < 2 {\n\t\t\tcontinue\n\t\t}\n\t\tif !IsLang(val[:2]) {\n\t\t\tcontinue\n\t\t}\n\t\tlng = val[:2]\n\t\tbreak\n\t}\n\treturn\n}\n"
  },
  {
    "path": "packages/migration/clb/applications_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar applicationsDataSQL = `\nINSERT INTO \"1_applications\" (id, name, conditions, ecosystem) VALUES (next_id('1_applications'), 'System', 'ContractConditions(\"MainCondition\")', '1');\n`\n"
  },
  {
    "path": "packages/migration/clb/clb_data_contracts.go",
    "content": "// Code generated by go generate; DO NOT EDIT.\n\npackage clb\n\nvar contractsDataSQL = `\nINSERT INTO \"1_contracts\" (id, name, value, token_id, conditions, app_id, ecosystem)\nVALUES\n\t(next_id('1_contracts'), 'AccessControlMode', 'contract AccessControlMode {\n    data {\n        VotingId int \"optional\"\n    }\n\n    func decentralizedAutonomous(){\n        if !DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":2}).Row(){\n            warning \"control mode DAO error\"\n        }\n        var prev string\n        prev = $stack[0]\n        if Len($stack) > 3{\n            prev = $stack[Len($stack) - 3]\n        }\n        if prev != \"@1VotingDecisionCheck\" {\n            warning LangRes(\"@1contract_start_votingdecisioncheck_only\")\n        }\n\n        $voting = DBFind(\"@1votings\").Where({\"ecosystem\": $ecosystem_id, \"id\": $VotingId,\"voting->name\":{\"$begin\":\"voting_for_control_mode_template\"}}).Columns(\"voting->type_decision,flags->success,voting->type\").Row()\n        if Int($voting[\"voting.type\"]) != 2 {\n            warning LangRes(\"@1voting_type_invalid\")\n        }\n        if Int($voting[\"voting.type_decision\"]) != 4 {\n            warning LangRes(\"@1voting_error_decision\")\n        }\n        if Int($voting[\"flags.success\"]) != 1 {\n            warning LangRes(\"@1voting_error_success\")\n        }\n    }\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n\n        if $control[\"control_mode\"] == 2 && $VotingId{\n            decentralizedAutonomous()\n            return\n        }\n        DeveloperCondition()\n    }\n    conditions {\n        $VotingId = Int($VotingId)\n        chooseControl()\n        $result = $control[\"control_mode\"]\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'AccessVoteTempRun', 'contract AccessVoteTempRun {\n    data {\n        ContractAccept string \"optional\"\n        ContractAcceptParams map \"optional\"\n    }\n\n    func votingCheck(){\n        var app_id int\n        app_id = Int(DBFind(\"@1applications\").Where({\"ecosystem\": $ecosystem_id, \"name\": \"Basic\"}).One(\"id\"))\n        $templateId = Int(DBFind(\"@1app_params\").Where({\"app_id\": app_id, \"name\": \"voting_template_control_mode\", \"ecosystem\": $ecosystem_id}).One(\"value\"))\n        if $templateId == 0 {\n            warning LangRes(\"@1template_id_not_found\")\n        }\n    }\n\n    action {\n        votingCheck()\n        var temp map\n        temp[\"TemplateId\"] = $templateId\n        temp[\"Duration\"] = 7\n        temp[\"ContractAccept\"] = $ContractAccept\n        temp[\"ContractAcceptParams\"] = JSONEncode($ContractAcceptParams)\n        CallContract(\"@1VotingTemplateRun\",temp)\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'BindWallet', 'contract BindWallet {\n\tdata {\n\t\tId  int\n\t}\n\tconditions {\n\t\t$cur = DBRow(\"contracts\").Columns(\"id,conditions,wallet_id\").WhereId($Id)\n\t\tif !$cur {\n\t\t\terror Sprintf(\"Contract %d does not exist\", $Id)\n\t\t}\n\t\tEval($cur[\"conditions\"])\n\t\tif $key_id != Int($cur[\"wallet_id\"]) {\n\t\t\terror Sprintf(\"Wallet %d cannot activate the contract\", $key_id)\n\t\t}\n\t}\n\taction {\n\t\tBndWallet($Id, $ecosystem_id)\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'CallDelayedContract', 'contract CallDelayedContract {\n\tdata {\n        Id int\n\t}\n\n\tconditions {\n\t\tHonorNodeCondition()\n\n\t\tvar rows array\n\t\trows = DBFind(\"@1delayed_contracts\").Where({\"id\": $Id, \"deleted\": 0})\n\n\t\tif !Len(rows) {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_not_exist\"), $Id)\n\t\t}\n\t\t$cur = rows[0]\n\t\t$limit = Int($cur[\"limit\"])\n\t\t$counter = Int($cur[\"counter\"])\n\n\t\tif $block < Int($cur[\"block_id\"]) {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_error\"), $Id, $cur[\"block_id\"], $block)\n\t\t}\n\n\t\tif $limit > 0 && $counter >= $limit {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_limited\"), $Id)\n\t\t}\n\t}\n\n\taction {\n\t\t$counter = $counter + 1\n\n\t\tvar block_id int\n\t\tblock_id = $block\n\t\tif $limit == 0 || $limit > $counter {\n\t\t\tblock_id = block_id + Int($cur[\"every_block\"])\n\t\t}\n\n\t\tDBUpdate(\"@1delayed_contracts\", $Id, {\"counter\": $counter, \"block_id\": block_id})\n\n\t\tvar params map\n\t\tCallContract($cur[\"contract\"], params)\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'CheckNodesBan', 'contract CheckNodesBan {\n    func getPermission() {\n        var array_permissions array result i int prevContract string\n        array_permissions = [\"@1CheckNodesBan\"]\n\n        prevContract = $stack[0]\n        if Len($stack) > 2 {\n            prevContract = $stack[Len($stack) - 2]\n        }\n        while i < Len(array_permissions) {\n            var contract_name string\n            contract_name = array_permissions[i]\n            if contract_name == prevContract {\n                result = 1\n            }\n            i = i + 1\n        }\n\n        if result == 0 {\n            warning LangRes(\"@1contract_chain_distorted\")\n        }\n    }\n    conditions {\n        getPermission()\n        HonorNodeCondition()\n        var rows array\n        rows = DBFind(\"@1delayed_contracts\").Where({\"contract\": \"@1CheckNodesBan\", \"deleted\": 0})\n        if !Len(rows) {\n            warning Sprintf(LangRes(\"@1template_delayed_contract_not_exist\"), $Id)\n        }\n        $cur = rows[0]\n        $counter = Int($cur[\"counter\"]) + 1\n        $Id = Int($cur[\"id\"])\n    }\n    action {\n        DBUpdateExt(\"@1delayed_contracts\", {\"id\":$Id}, {\"counter\": $counter})\n\n        UpdateNodesBan($block_time)\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditAppParam', 'contract EditAppParam {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"app_params\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"app_params\", $Id, pars)\n        }\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditApplication', 'contract EditApplication {\n    data {\n        ApplicationId int\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && false\n    }\n\n    conditions {\n        RowConditions(\"applications\", $ApplicationId, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"applications\", $ApplicationId, pars)\n        }\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditColumn', 'contract EditColumn {\n    data {\n        TableName string\n        Name string\n        Permissions string\n    }\n\n    conditions {\n        ColumnCondition($TableName, $Name, \"\", $Permissions)\n    }\n\n    action {\n        PermColumn($TableName, $Name, $Permissions)\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditContract', 'contract EditContract {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"contracts\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        $cur = DBFind(\"contracts\").Columns(\"id,value,conditions,wallet_id,token_id\").WhereId($Id).Row()\n        if !$cur {\n            error Sprintf(\"Contract %d does not exist\", $Id)\n        }\n        if $Value {\n            ValidateEditContractNewValue($Value, $cur[\"value\"])\n        }\n   \n        $recipient = Int($cur[\"wallet_id\"])\n    }\n\n    action {\n        UpdateContract($Id, $Value, $Conditions, $recipient, $cur[\"token_id\"])\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditCron', 'contract EditCron {\n\t\tdata {\n\t\t\tId         int\n\t\t\tContract   string\n\t\t\tCron       string \"optional\"\n\t\t\tLimit      int \"optional\"\n\t\t\tTill       string \"optional date\"\n\t\t\tConditions string\n\t\t}\n\t\tconditions {\n\t\t\tConditionById(\"cron\", true)\n\t\t\tValidateCron($Cron)\n\t\t}\n\t\taction {\n\t\t\tif !$Till {\n\t\t\t\t$Till = \"1970-01-01 00:00:00\"\n\t\t\t}\n\t\t\tif !HasPrefix($Contract, \"@\") {\n\t\t\t\t$Contract = \"@\" + Str($ecosystem_id) + $Contract\n\t\t\t}\n\t\t\tDBUpdate(\"cron\", $Id, {\"cron\": $Cron,\"contract\": $Contract,\n\t\t\t    \"counter\":$Limit, \"till\": $Till, \"conditions\":$Conditions})\n\t\t\tUpdateCron($Id)\n\t\t}\n\t}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditLang', 'contract EditLang {\n    data {\n        Id int\n        Trans string\n    }\n\n    conditions {\n        EvalCondition(\"parameters\", \"changing_language\", \"value\")\n        $lang = DBFind(\"languages\").Where({id: $Id}).Row()\n    }\n\n    action {\n        EditLanguage($Id, $lang[\"name\"], $Trans)\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditMenu', 'contract EditMenu {\n    data {\n        Id int\n        Value string \"optional\"\n        Title string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value && !$Title\n    }\n\n    conditions {\n        RowConditions(\"menu\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Title {\n            pars[\"title\"] = $Title\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"menu\", $Id, pars)\n        }            \n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditPage', 'contract EditPage {\n    data {\n        Id int\n        Value string \"optional\"\n        Menu string \"optional\"\n        Conditions string \"optional\"\n        ValidateCount int \"optional\"\n        ValidateMode string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value && !$Menu && !$ValidateCount \n    }\n    func preparePageValidateCount(count int) int {\n        var min, max int\n        min = Int(EcosysParam(\"min_page_validate_count\"))\n        max = Int(EcosysParam(\"max_page_validate_count\"))\n        if count < min {\n            count = min\n        } else {\n            if count > max {\n                count = max\n            }\n        }\n        return count\n    }\n\n    conditions {\n        RowConditions(\"pages\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        $ValidateCount = preparePageValidateCount($ValidateCount)\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Menu {\n            pars[\"menu\"] = $Menu\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if $ValidateCount {\n            pars[\"validate_count\"] = $ValidateCount\n        }\n        if $ValidateMode {\n            if $ValidateMode != \"1\" {\n                $ValidateMode = \"0\"\n            }\n            pars[\"validate_mode\"] = $ValidateMode\n        }\n        if pars {\n            DBUpdate(\"pages\", $Id, pars)\n        }\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditParameter', 'contract EditParameter {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        DeveloperCondition()\n\n        RowConditions(\"@1parameters\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        if $Value {\n            $Name = DBFind(\"@1parameters\").Where({\"id\": $Id, \"ecosystem\": $ecosystem_id}).One(\"name\")\n            if $Name == \"founder_account\" {\n                var account string\n                account = IdToAddress(Int($Value))\n                if !DBFind(\"@1keys\").Where({\"account\": account, \"ecosystem\": $ecosystem_id, \"deleted\": 0}).One(\"id\") {\n                    warning Sprintf(LangRes(\"@1template_user_not_found\"), $Value)\n                }\n            }\n            if $Name == \"max_block_user_tx\" || $Name == \"money_digit\" || $Name == \"max_sum\" || $Name == \"min_page_validate_count\" || $Name == \"max_page_validate_count\" {\n                if Size($Value) == 0 {\n                    warning LangRes(\"@1value_not_received\")\n                }\n                if Int($Value) <= 0 {\n                    warning LangRes(\"@1value_must_greater_zero\")\n                }\n            }\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            if $Value == ` + \"`\" + `\"\"` + \"`\" + ` {\n                pars[\"value\"] = \"\"\n            } else {\n                pars[\"value\"] = $Value\n            }\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"@1parameters\", $Id, pars)\n        }\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditSnippet', 'contract EditSnippet {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"snippets\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"snippets\", $Id, pars)\n        }\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'EditTable', 'contract EditTable {\n    data {\n        Name string\n        InsertPerm string\n        UpdatePerm string\n        NewColumnPerm string\n        ReadPerm string \"optional\"\n    }\n\n    conditions {\n        if !$InsertPerm {\n            info(\"Insert condition is empty\")\n        }\n        if !$UpdatePerm {\n            info(\"Update condition is empty\")\n        }\n        if !$NewColumnPerm {\n            info(\"New column condition is empty\")\n        }\n\n        var permissions map\n        permissions[\"insert\"] = $InsertPerm\n        permissions[\"update\"] = $UpdatePerm\n        permissions[\"new_column\"] = $NewColumnPerm\n        if $ReadPerm {\n            permissions[\"read\"] = $ReadPerm\n        }\n        $Permissions = permissions\n        TableConditions($Name, \"\", JSONEncode($Permissions))\n    }\n\n    action {\n        PermTable($Name, JSONEncode($Permissions))\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'HonorNodeCondition', 'contract HonorNodeCondition {\n\tconditions {\n\t\tvar account_key int\n\t\taccount_key = AddressToId($account_id)\n\t\tif IsHonorNodeKey(account_key) {\n\t\t\treturn\n\t\t}\n\t\twarning \"HonorNodeCondition: Sorry, you do not have access to this action\"\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'Import', 'contract Import {\n    data {\n        Data string\n    }\n    conditions {\n        $ApplicationId = 0\n        var app_map map\n        app_map = DBFind(\"@1buffer_data\").Columns(\"value->app_name\").Where({\"key\": \"import_info\", \"account\": $account_id, \"ecosystem\": $ecosystem_id}).Row()\n        if app_map {\n            var app_id int ival string\n            ival = Str(app_map[\"value.app_name\"])\n            app_id = Int(DBFind(\"@1applications\").Columns(\"id\").Where({\"name\": ival, \"ecosystem\": $ecosystem_id}).One(\"id\"))\n            if app_id {\n                $ApplicationId = app_id\n            }\n        }\n    }\n    action {\n        var editors, creators map\n        editors[\"pages\"] = \"EditPage\"\n        editors[\"snippets\"] = \"EditSnippet\"\n        editors[\"menu\"] = \"EditMenu\"\n        editors[\"app_params\"] = \"EditAppParam\"\n        editors[\"languages\"] = \"EditLang\"\n        editors[\"contracts\"] = \"EditContract\"\n        editors[\"tables\"] = \"\" // nothing\n        creators[\"pages\"] = \"NewPage\"\n        creators[\"snippets\"] = \"NewSnippet\"\n        creators[\"menu\"] = \"NewMenu\"\n        creators[\"app_params\"] = \"NewAppParam\"\n        creators[\"languages\"] = \"NewLang\"\n        creators[\"contracts\"] = \"NewContract\"\n        creators[\"tables\"] = \"NewTable\"\n        var dataImport array\n        dataImport = JSONDecode($Data)\n        var i int\n        while i < Len(dataImport) {\n            var item cdata map type name string\n            cdata = dataImport[i]\n            if cdata {\n                cdata[\"ApplicationId\"] = $ApplicationId\n                type = cdata[\"Type\"]\n                name = cdata[\"Name\"]\n                // Println(Sprintf(\"import %v: %v\", type, cdata[\"Name\"]))\n                var tbl string\n                tbl = \"@1\" + Str(type)\n                if type == \"app_params\" {\n                    item = DBFind(tbl).Where({\"name\": name, \"ecosystem\": $ecosystem_id, \"app_id\": $ApplicationId}).Row()\n                } else {\n                    item = DBFind(tbl).Where({\"name\": name, \"ecosystem\": $ecosystem_id}).Row()\n                }\n                var contractName string\n                if item {\n                    contractName = editors[type]\n                    cdata[\"Id\"] = Int(item[\"id\"])\n                    if type == \"contracts\" {\n                        if item[\"conditions\"] == \"false\" {\n                            // ignore updating impossible\n                            contractName = \"\"\n                        }\n                    } elif type == \"menu\" {\n                        var menu menuItem string\n                        menu = Replace(item[\"value\"], \" \", \"\")\n                        menu = Replace(menu, \"\\n\", \"\")\n                        menu = Replace(menu, \"\\r\", \"\")\n                        menuItem = Replace(cdata[\"Value\"], \" \", \"\")\n                        menuItem = Replace(menuItem, \"\\n\", \"\")\n                        menuItem = Replace(menuItem, \"\\r\", \"\")\n                        if Contains(menu, menuItem) {\n                            // ignore repeated\n                            contractName = \"\"\n                        } else {\n                            cdata[\"Value\"] = item[\"value\"] + \"\\n\" + cdata[\"Value\"]\n                        }\n                    }\n                } else {\n                    contractName = creators[type]\n                }\n                if contractName != \"\" {\n                    CallContract(contractName, cdata)\n                }\n            }\n            i = i + 1\n        }\n        // Println(Sprintf(\"> time: %v\", $time))\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'ImportUpload', 'contract ImportUpload {\n    data {\n        Data file\n    }\n    conditions {\n        $Body = BytesToString($Data[\"Body\"])\n        $limit = 10 // data piece size of import\n    }\n    action {\n        // init buffer_data, cleaning old buffer\n        var initJson map\n        $import_id = Int(DBFind(\"@1buffer_data\").Where({\"account\": $account_id, \"key\": \"import\", \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $import_id {\n             DBUpdate(\"@1buffer_data\", $import_id, {\"value\": initJson})\n        } else {\n            $import_id = DBInsert(\"@1buffer_data\", {\"account\": $account_id, \"key\": \"import\", \"value\": initJson, \"ecosystem\": $ecosystem_id})\n        }\n        $info_id = Int(DBFind(\"@1buffer_data\").Where({\"account\": $account_id, \"key\": \"import_info\", \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $info_id {\n            DBUpdate(\"@1buffer_data\", $info_id, {\"value\": initJson})\n        } else {\n            $info_id = DBInsert(\"@1buffer_data\", {\"account\": $account_id, \"key\": \"import_info\", \"value\": initJson, \"ecosystem\": $ecosystem_id})\n        }\n        var input map arrData array\n        input = JSONDecode($Body)\n        arrData = input[\"data\"]\n        var pages_arr blocks_arr menu_arr parameters_arr languages_arr contracts_arr tables_arr array\n        // IMPORT INFO\n        var i lenArrData int item map\n        lenArrData = Len(arrData)\n        while i < lenArrData {\n            item = arrData[i]\n            if item[\"Type\"] == \"pages\" {\n                pages_arr = Append(pages_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"snippets\" {\n                blocks_arr = Append(blocks_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"menu\" {\n                menu_arr = Append(menu_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"app_params\" {\n                parameters_arr = Append(parameters_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"languages\" {\n                languages_arr = Append(languages_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"contracts\" {\n                contracts_arr = Append(contracts_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"tables\" {\n                tables_arr = Append(tables_arr, item[\"Name\"])\n            }\n            i = i + 1\n        }\n        var inf map\n        inf[\"app_name\"] = input[\"name\"]\n        inf[\"pages\"] = Join(pages_arr, \", \")\n        inf[\"pages_count\"] = Len(pages_arr)\n        inf[\"snippets\"] = Join(blocks_arr, \", \")\n        inf[\"blocks_count\"] = Len(blocks_arr)\n        inf[\"menu\"] = Join(menu_arr, \", \")\n        inf[\"menu_count\"] = Len(menu_arr)\n        inf[\"parameters\"] = Join(parameters_arr, \", \")\n        inf[\"parameters_count\"] = Len(parameters_arr)\n        inf[\"languages\"] = Join(languages_arr, \", \")\n        inf[\"languages_count\"] = Len(languages_arr)\n        inf[\"contracts\"] = Join(contracts_arr, \", \")\n        inf[\"contracts_count\"] = Len(contracts_arr)\n        inf[\"tables\"] = Join(tables_arr, \", \")\n        inf[\"tables_count\"] = Len(tables_arr)\n        if 0 == inf[\"pages_count\"] + inf[\"blocks_count\"] + inf[\"menu_count\"] + inf[\"parameters_count\"] + inf[\"languages_count\"] + inf[\"contracts_count\"] + inf[\"tables_count\"] {\n            warning \"Invalid or empty import file\"\n        }\n        // IMPORT DATA\n        // the contracts is imported in one piece, the rest is cut under the $limit\n        var sliced contracts array\n        i = 0\n        while i < lenArrData {\n            var items array l int item map\n            while l < $limit && (i + l < lenArrData) {\n                item = arrData[i + l]\n                if item[\"Type\"] == \"contracts\" {\n                    contracts = Append(contracts, item)\n                } else {\n                    items = Append(items, item)\n                }\n                l = l + 1\n            }\n            var batch map\n            batch[\"Data\"] = JSONEncode(items)\n            sliced = Append(sliced, batch)\n            i = i + $limit\n        }\n        if Len(contracts) > 0 {\n            var batch map\n            batch[\"Data\"] = JSONEncode(contracts)\n            sliced = Append(sliced, batch)\n        }\n        input[\"data\"] = sliced\n        // storing\n        DBUpdate(\"@1buffer_data\", $import_id, {\"value\": input})\n        DBUpdate(\"@1buffer_data\", $info_id, {\"value\": inf})\n        var name string\n        name = Str(input[\"name\"])\n        var cndns string\n        cndns = Str(input[\"conditions\"])\n        if !DBFind(\"@1applications\").Columns(\"id\").Where({\"name\": name, \"ecosystem\": $ecosystem_id}).One(\"id\") {\n            DBInsert(\"@1applications\", {\"name\": name, \"conditions\": cndns, \"ecosystem\": $ecosystem_id})\n        }\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'ListCLB', 'contract ListCLB {\n\t\tdata {}\n\t\n\t\tconditions {}\n\t\n\t\taction {\n\t\t\t$result = GetCLBList()\n\t\t}\n\t}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'MainCondition', 'contract MainCondition {\n\t\tconditions {\n\t\t  if EcosysParam(\"founder_account\")!=$key_id\n\t\t  {\n\t\t\twarning \"Sorry, you do not have access to this action.\"\n\t\t  }\n\t\t}\n\t  }\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewAppParam', 'contract NewAppParam {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"app_params\").Columns(\"id\").Where({\"name\":$Name}).One(\"id\") {\n            warning Sprintf( \"Application parameter %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"app_params\", {app_id: $ApplicationId, name: $Name, value: $Value,\n              conditions: $Conditions})\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewApplication', 'contract NewApplication {\n    data {\n        Name string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if Size($Name) == 0 {\n            warning \"Application name missing\"\n        }\n\n        if DBFind(\"applications\").Columns(\"id\").Where({name:$Name}).One(\"id\") {\n            warning Sprintf( \"Application %s already exists\", $Name)\n        }\n    }\n\n    action {\n        $result = DBInsert(\"applications\", {name: $Name,conditions: $Conditions})\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewBadBlock', 'contract NewBadBlock {\n\tdata {\n\t\tProducerNodeID int\n\t\tConsumerNodeID int\n\t\tBlockID int\n\t\tTimestamp int\n\t\tReason string\n\t}\n\taction {\n        DBInsert(\"@1bad_blocks\", {producer_node_id: $ProducerNodeID,consumer_node_id: $ConsumerNodeID,\n            block_id: $BlockID, \"timestamp block_time\": $Timestamp, reason: $Reason})\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewCLB', 'contract NewCLB {\n\t\tdata {\n\t\t\tCLBName string\n\t\t\tDBUser string\n\t\t\tDBPassword string\n\t\t\tCLBAPIPort int\n\t\t}\n\t\n\t\tconditions {\n            if Size($CLBName) == 0 {\n                warning \"CLBName was not received\"\n            }\n            if Contains($CLBName, \" \") {\n                error \"CLBName can not contain spaces\"\n            }\n            if Size($DBUser) == 0 {\n                warning \"DBUser was not received\"\n            }\n            if Size($DBPassword) == 0 {\n                warning \"DBPassword was not received\"\n            }\n            if $CLBAPIPort <= 0  {\n                warning \"CLB API PORT not received\"\n            }\n            \n\t\t}\n\t\n\t\taction {\n            $CLBName = ToLower($CLBName)\n            $DBUser = ToLower($DBUser)\n            CreateCLB($CLBName, $DBUser, $DBPassword, $CLBAPIPort)\n            $result = \"CLB \" + $CLBName + \" created\"\n\t\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewContract', 'contract NewContract {\n    data {\n        ApplicationId int\n        Value string\n        Conditions string\n        TokenEcosystem int \"optional\"\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        $contract_name = ContractName($Value)\n\n        if !$contract_name {\n            error \"must be the name\"\n        }\n\n        if !$TokenEcosystem {\n            $TokenEcosystem = 1\n        } else {\n            if !SysFuel($TokenEcosystem) {\n                warning Sprintf(\"Ecosystem %d is not system\", $TokenEcosystem)\n            }\n        }\n    }\n\n    action {\n        $result = CreateContract($contract_name, $Value, $Conditions, $TokenEcosystem, $ApplicationId)\n    }\n    func price() int {\n        return SysParamInt(\"contract_price\")\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewCron', 'contract NewCron {\n\t\tdata {\n\t\t\tCron       string\n\t\t\tContract   string\n\t\t\tLimit      int \"optional\"\n\t\t\tTill       string \"optional date\"\n\t\t\tConditions string\n\t\t}\n\t\tconditions {\n\t\t\tValidateCondition($Conditions,$ecosystem_id)\n\t\t\tValidateCron($Cron)\n\t\t}\n\t\taction {\n\t\t\tif !$Till {\n\t\t\t\t$Till = \"1970-01-01 00:00:00\"\n\t\t\t}\n\t\t\tif !HasPrefix($Contract, \"@\") {\n\t\t\t\t$Contract = \"@\" + Str($ecosystem_id) + $Contract\n\t\t\t}\n\t\t\t$result = DBInsert(\"cron\", {owner: $key_id,cron:$Cron,contract: $Contract,\n\t\t\t\tcounter:$Limit, till: $Till,conditions: $Conditions})\n\t\t\tUpdateCron($result)\n\t\t}\n\t}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewEcosystem', 'contract NewEcosystem {\n\tdata {\n\t\tName  string\n\t}\n\taction {\n\t\t$result = CreateEcosystem($key_id, $Name)\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewLang', 'contract NewLang {\n    data {\n        ApplicationId int\n        Name string\n        Trans string\n    }\n\n    conditions {\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"languages\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Language resource %s already exists\", $Name)\n        }\n\n        EvalCondition(\"parameters\", \"changing_language\", \"value\")\n    }\n\n    action {\n        CreateLanguage($Name, $Trans)\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewMenu', 'contract NewMenu {\n    data {\n        Name string\n        Value string\n        Title string \"optional\"\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if DBFind(\"menu\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Menu %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"menu\", {name:$Name,value: $Value, title: $Title, conditions: $Conditions})\n    }\n    func price() int {\n        return SysParamInt(\"menu_price\")\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewPage', 'contract NewPage {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Menu string\n        Conditions string\n        ValidateCount int \"optional\"\n        ValidateMode string \"optional\"\n    }\n    func preparePageValidateCount(count int) int {\n        var min, max int\n        min = Int(EcosysParam(\"min_page_validate_count\"))\n        max = Int(EcosysParam(\"max_page_validate_count\"))\n\n        if count < min {\n            count = min\n        } else {\n            if count > max {\n                count = max\n            }\n        }\n        return count\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"pages\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Page %s already exists\", $Name)\n        }\n\n        $ValidateCount = preparePageValidateCount($ValidateCount)\n\n        if $ValidateMode {\n            if $ValidateMode != \"1\" {\n                $ValidateMode = \"0\"\n            }\n        }\n    }\n\n    action {\n        DBInsert(\"pages\", {name: $Name,value: $Value, menu: $Menu,\n             validate_count:$ValidateCount,validate_mode: $ValidateMode,\n             conditions: $Conditions,app_id: $ApplicationId})\n    }\n    func price() int {\n        return SysParamInt(\"page_price\")\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewParameter', 'contract NewParameter {\n    data {\n        Name string\n        Value string\n        Conditions string\n    }\n    func warnEmpty(name value string) {\n        if Size(value) == 0 {\n            warning Sprintf(LangRes(\"@1x_parameter_empty\"),name)\n        }\n    }\n    conditions {\n        DeveloperCondition()\n\n        ValidateCondition($Conditions, $ecosystem_id)\n        $Name = TrimSpace($Name)\n        warnEmpty(\"Name\",$Name)\n        if DBFind(\"@1parameters\").Where({\"name\": $Name, \"ecosystem\": $ecosystem_id}).One(\"id\") {\n            warning Sprintf(LangRes(\"@1template_parameter_exists\"), $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"@1parameters\", {\"name\": $Name, \"value\": $Value, \"conditions\": $Conditions, \"ecosystem\": $ecosystem_id})\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewSnippet', 'contract NewSnippet {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"snippets\").Columns(\"id\").Where({name:$Name}).One(\"id\") {\n            warning Sprintf( \"Block %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"snippets\", {name: $Name, value: $Value, conditions: $Conditions,\n              app_id: $ApplicationId})\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewTable', 'contract NewTable {\n    data {\n        ApplicationId int\n        Name string\n        Columns string\n        Permissions string\n    }\n    conditions {\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n        TableConditions($Name, $Columns, $Permissions)\n    }\n    \n    action {\n        CreateTable($Name, $Columns, $Permissions, $ApplicationId)\n    }\n    func price() int {\n        return SysParamInt(\"table_price\")\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NewUser', 'contract NewUser {\n\tdata {\n\t\tNewPubkey string\n\t}\n\tconditions {\n\t\t$id = PubToID($NewPubkey)\n\t\tif $id == 0 {\n\t\t\terror \"Wrong pubkey\"\n\t\t}\n\t\tif DBFind(\"keys\").Columns(\"id\").WhereId($id).One(\"id\") {\n\t\t\terror \"User already exists\"\n\t\t}\n\t}\n\taction {\n\t\t$pub = HexToPub($NewPubkey)\n\t\t$account = IdToAddress($id)\n\t\t$amount = Money(0)\n\n\t\tDBInsert(\"keys\", {\n\t\t\t\"id\": $id,\n\t\t\t\"account\": $account,\n\t\t\t\"pub\": $pub,\n\t\t\t\"amount\": $amount,\n\t\t\t\"ecosystem\": 1\n\t\t})\n\t}\n}\n', '%[1]d', 'ContractConditions(\"NodeOwnerCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'NodeOwnerCondition', 'contract NodeOwnerCondition {\n\tconditions {\n        $raw_honor_nodes = SysParamString(\"honor_nodes\")\n        if Size($raw_honor_nodes) == 0 {\n            ContractConditions(\"MainCondition\")\n        } else {\n            $honor_nodes = JSONDecode($raw_honor_nodes)\n            var i int\n            while i < Len($honor_nodes) {\n                $fn = $honor_nodes[i]\n                if $fn[\"key_id\"] == $key_id {\n                    return true\n                }\n                i = i + 1\n            }\n            warning \"NodeOwnerCondition: Sorry, you do not have access to this action.\"\n        }\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'RemoveCLB', 'contract RemoveCLB {\n\tdata {\n\t\t\tCLBName string\n\t}\n\tconditions {}\n\taction{\n        $CLBName = ToLower($CLBName)\n        DeleteCLB($CLBName)\n        $result = \"CLB \" + $CLBName + \" removed\"\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'RunCLB', 'contract RunCLB {\n\tdata {\n\t\tCLBName string\n\t}\t\n\tconditions {\n\t}\t\n\taction {\n\t\t$CLBName = ToLower($CLBName)\n\t\tStartCLB($CLBName)\n\t\t$result = \"CLB \" + $CLBName + \" running\"\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'StopCLB', 'contract StopCLB {\n\t\tdata {\n\t\t\tCLBName string\n\t\t}\n\t\n\t\tconditions {\n\t\t}\n\t\n\t\taction {\n\t\t\t$CLBName = ToLower($CLBName)\n\t\t\tStopCLBProcess($CLBName)\n\t\t\t$result = \"CLB \" + $CLBName + \" stopped\"\n\t\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'UnbindWallet', 'contract UnbindWallet {\n\tdata {\n\t\tId         int\n\t}\n\tconditions {\n\t\t$cur = DBRow(\"contracts\").Columns(\"id,conditions,wallet_id\").WhereId($Id)\n\t\tif !$cur {\n\t\t\terror Sprintf(\"Contract %d does not exist\", $Id)\n\t\t}\n\t\t\n\t\tEval($cur[\"conditions\"])\n\t\tif $key_id != Int($cur[\"wallet_id\"]) {\n\t\t\terror Sprintf(\"Wallet %d cannot deactivate the contract\", $key_id)\n\t\t}\n\t}\n\taction {\n\t\tUnbndWallet($Id, $ecosystem_id)\n\t}\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'UpdatePlatformParam', 'contract UpdatePlatformParam {\n     data {\n        Name string\n        Value string\n        Conditions string \"optional\"\n     }\n     conditions {\n         if !GetContractByName($Name){\n            warning \"System parameter not found\"\n         }\n     }\n     action {\n        var params map\n        params[\"Value\"] = $Value\n        CallContract($Name, params)\n        \n        DBUpdatePlatformParam($Name, $Value, $Conditions)\n     }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'UploadBinary', 'contract UploadBinary {\n    data {\n        ApplicationId int\n        Name string\n        Data bytes\n        DataMimeType string \"optional\"\n        MemberAccount string \"optional\"\n    }\n    conditions {\n        if Size($MemberAccount) > 0 {\n            $UserID = $MemberAccount\n        } else {\n            $UserID = $account_id\n        }\n        $Id = Int(DBFind(\"@1binaries\").Columns(\"id\").Where({\"app_id\": $ApplicationId, \n                \"account\": $UserID, \"name\": $Name, \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $Id == 0 {\n            if $ApplicationId == 0 {\n                warning LangRes(\"@1aid_cannot_zero\")\n            }\n        }\n    }\n    action {\n        var hash string\n        hash = Hash($Data)\n        if $DataMimeType == \"\" {\n            $DataMimeType = \"application/octet-stream\"\n        }\n        if $Id != 0 {\n            DBUpdate(\"@1binaries\", $Id, {\"data\": $Data, \"hash\": hash, \"mime_type\": $DataMimeType})\n        } else {\n            $Id = DBInsert(\"@1binaries\", {\"app_id\": $ApplicationId, \"account\": $UserID,\n                \"name\": $Name, \"data\": $Data, \"hash\": hash, \"mime_type\": $DataMimeType, \"ecosystem\": $ecosystem_id})\n        }\n        $result = $Id\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d'),\n\t(next_id('1_contracts'), 'UploadFile', 'contract UploadFile {\n    data {\n        ApplicationId int\n        Data file\n        Name string \"optional\"\n    }\n    conditions {\n        if $Name == \"\" {\n            $Name = $Data[\"Name\"]\n        }\n        $Body = $Data[\"Body\"]\n        $DataMimeType = $Data[\"MimeType\"]\n    }\n    action {\n        $Id = @1UploadBinary(\"ApplicationId,Name,Data,DataMimeType\", $ApplicationId, $Name, $Body, $DataMimeType)\n        $result = $Id\n    }\n}\n', '%[1]d', 'ContractConditions(\"MainCondition\")', '1', '%[1]d');\n`"
  },
  {
    "path": "packages/migration/clb/data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar (\n\tmigrationInitial = `\n\t\tDROP SEQUENCE IF EXISTS migration_history_id_seq CASCADE;\n\t\tCREATE SEQUENCE migration_history_id_seq START WITH 1;\n\t\tDROP TABLE IF EXISTS \"migration_history\";\n\t\tCREATE TABLE \"migration_history\" (\n\t\t\t\"id\" int NOT NULL default nextval('migration_history_id_seq'),\n\t\t\t\"version\" varchar(255) NOT NULL,\n\t\t\t\"date_applied\" int NOT NULL\n\t\t);\n\t\tALTER SEQUENCE migration_history_id_seq owned by migration_history.id;\n\t\tALTER TABLE ONLY \"migration_history\" ADD CONSTRAINT migration_history_pkey PRIMARY KEY (id);`\n\n\tmigrationInitialSchema = `\n\t\tCREATE TABLE \"system_contracts\" (\n\t\t\"id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"value\" text  NOT NULL DEFAULT '',\n\t\t\"wallet_id\" bigint NOT NULL DEFAULT '0',\n\t\t\"token_id\" bigint NOT NULL DEFAULT '0',\n\t\t\"active\" character(1) NOT NULL DEFAULT '0',\n\t\t\"conditions\" text  NOT NULL DEFAULT ''\n\t\t);\n\t\tALTER TABLE ONLY \"system_contracts\" ADD CONSTRAINT system_contracts_pkey PRIMARY KEY (id);\n\t\t\n\t\t\n\t\tCREATE TABLE \"system_tables\" (\n\t\t\"name\" varchar(100)  NOT NULL DEFAULT '',\n\t\t\"permissions\" jsonb,\n\t\t\"columns\" jsonb,\n\t\t\"conditions\" text  NOT NULL DEFAULT ''\n\t\t);\n\t\tALTER TABLE ONLY \"system_tables\" ADD CONSTRAINT system_tables_pkey PRIMARY KEY (name);\n\t\t\n\t\tDROP TABLE IF EXISTS \"install\"; CREATE TABLE \"install\" (\n\t\t\"progress\" varchar(10) NOT NULL DEFAULT ''\n\t\t);\n\t\t\n\t\tDROP TABLE IF EXISTS \"stop_daemons\"; CREATE TABLE \"stop_daemons\" (\n\t\t\"stop_time\" int NOT NULL DEFAULT '0'\n\t\t);`\n)\n"
  },
  {
    "path": "packages/migration/clb/keys_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n)\n\nvar keysDataSQL = `\nINSERT INTO \"1_keys\" (id, account, pub, blocked, ecosystem) \nVALUES (` + consts.GuestKey + `, '` + consts.GuestAddress + `', decode('` + consts.GuestPublic + `', 'hex'), 1, '%[1]d');\n`\n"
  },
  {
    "path": "packages/migration/clb/menu_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar menuDataSQL = `INSERT INTO \"1_menu\" (id, name, value, conditions, ecosystem) VALUES\n(next_id('1_menu'), 'admin_menu', 'MenuItem(Title:\"Application\", Page:apps_list, Icon:\"icon-folder\")\nMenuItem(Title:\"Ecosystem parameters\", Page:params_list, Icon:\"icon-settings\")\nMenuItem(Title:\"Menu\", Page:menus_list, Icon:\"icon-list\")\nMenuItem(Title:\"Confirmations\", Page:confirmations, Icon:\"icon-check\")\nMenuItem(Title:\"Import\", Page:import_upload, Icon:\"icon-cloud-upload\")\nMenuItem(Title:\"Export\", Page:export_resources, Icon:\"icon-cloud-download\")\nMenuGroup(Title:\"Resources\", Icon:\"icon-share\"){\n\tMenuItem(Title:\"Pages\", Page:app_pages, Icon:\"icon-screen-desktop\")\n\tMenuItem(Title:\"Blocks\", Page:app_blocks, Icon:\"icon-grid\")\n\tMenuItem(Title:\"Tables\", Page:app_tables, Icon:\"icon-docs\")\n\tMenuItem(Title:\"Contracts\", Page:app_contracts, Icon:\"icon-briefcase\")\n\tMenuItem(Title:\"Application parameters\", Page:app_params, Icon:\"icon-wrench\")\n\tMenuItem(Title:\"Language resources\", Page:app_langres, Icon:\"icon-globe\")\n\tMenuItem(Title:\"Binary data\", Page:app_binary, Icon:\"icon-layers\")\n}\nMenuItem(Title:\"Dashboard\", Page:admin_dashboard, Icon:\"icon-wrench\")', 'ContractConditions(\"MainCondition\")', '%[1]d');\n`\n"
  },
  {
    "path": "packages/migration/clb/pages_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\n/*\nvar pagesDataSQL = `INSERT INTO \"1_pages\" (id, name, value, menu, conditions, app_id, ecosystem) VALUES\n\t(next_id('1_pages'), 'admin_index', '', 'admin_menu', 'ContractConditions(\"@1DeveloperCondition\")', '%[5]d', '%[1]d'),\n\t(next_id('1_pages'), 'developer_index', '', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '%[5]d', '%[1]d'),\n\t(next_id('1_pages'), 'notifications', '', 'default_menu', 'ContractConditions(\"@1DeveloperCondition\")', '%[5]d', '%[1]d'),\n\t(next_id('1_pages'), 'import_app', 'Div(content-wrapper){\n    DBFind(@1buffer_data).Columns(\"id,value->name,value->data\").Where({\"key\": import, \"account\": #account_id#, \"ecosystem\": #ecosystem_id#}).Vars(import)\n    DBFind(@1buffer_data).Columns(\"value->app_name,value->pages,value->pages_count,value->blocks,value->blocks_count,value->menu,value->menu_count,value->parameters,value->parameters_count,value->languages,value->languages_count,value->contracts,value->contracts_count,value->tables,value->tables_count\").Where({\"key\": import_info, \"account\": #account_id#, \"ecosystem\": #ecosystem_id#}).Vars(info)\n\n    SetTitle(\"Import - #info_value_app_name#\")\n    Data(data_info, \"DataName,DataCount,DataInfo\"){\n        Pages,\"#info_value_pages_count#\",\"#info_value_pages#\"\n        Blocks,\"#info_value_blocks_count#\",\"#info_value_blocks#\"\n        Menu,\"#info_value_menu_count#\",\"#info_value_menu#\"\n        Parameters,\"#info_value_parameters_count#\",\"#info_value_parameters#\"\n        Language resources,\"#info_value_languages_count#\",\"#info_value_languages#\"\n        Contracts,\"#info_value_contracts_count#\",\"#info_value_contracts#\"\n        Tables,\"#info_value_tables_count#\",\"#info_value_tables#\"\n    }\n    Div(breadcrumb){\n        Span(Class: text-muted, Body: \"Your data that you can import\")\n    }\n\n    Div(panel panel-primary){\n        ForList(data_info){\n            Div(list-group-item){\n                Div(row){\n                    Div(col-md-10 mc-sm text-left){\n                        Span(Class: text-bold, Body: \"#DataName#\")\n                    }\n                    Div(col-md-2 mc-sm text-right){\n                        If(#DataCount# > 0){\n                            Span(Class: text-bold, Body: \"(#DataCount#)\")\n                        }.Else{\n                            Span(Class: text-muted, Body: \"(0)\")\n                        }\n                    }\n                }\n                Div(row){\n                    Div(col-md-12 mc-sm text-left){\n                        If(#DataCount# > 0){\n                            Span(Class: h6, Body: \"#DataInfo#\")\n                        }.Else{\n                            Span(Class: text-muted h6, Body: \"Nothing selected\")\n                        }\n                    }\n                }\n            }\n        }\n        If(#import_id# > 0){\n            Div(list-group-item text-right){\n                VarAsIs(imp_data, \"#import_value_data#\")\n                Button(Body: \"Import\", Class: btn btn-primary, Page: @1apps_list).CompositeContract(@1Import, \"#imp_data#\")\n            }\n        }\n    }\n}', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '%[5]d', '%[1]d'),\n\t(next_id('1_pages'), 'import_upload', 'Div(content-wrapper){\n        SetTitle(\"Import\")\n        Div(breadcrumb){\n            Span(Class: text-muted, Body: \"Select payload that you want to import\")\n        }\n        Form(panel panel-primary){\n            Div(list-group-item){\n                Input(Name: Data, Type: file)\n            }\n            Div(list-group-item text-right){\n                Button(Body: \"Load\", Class: btn btn-primary, Contract: @1ImportUpload, Page: @1import_app)\n            }\n        }\n    }', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1');\n`\n*/\n\nvar pagesDataSQL = `INSERT INTO \"1_pages\" (id, name, value, menu, conditions, app_id, ecosystem) VALUES\n\t(next_id('1_pages'), 'admin_index', '', 'admin_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1'),\n\t(next_id('1_pages'), 'developer_index', '', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1'),\n\t(next_id('1_pages'), 'notifications', '', 'default_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1'),\n\t(next_id('1_pages'), 'import_app', 'Div(content-wrapper){\n    DBFind(@1buffer_data).Columns(\"id,value->name,value->data\").Where({\"key\": import, \"account\": #account_id#, \"ecosystem\": #ecosystem_id#}).Vars(import)\n    DBFind(@1buffer_data).Columns(\"value->app_name,value->pages,value->pages_count,value->blocks,value->blocks_count,value->menu,value->menu_count,value->parameters,value->parameters_count,value->languages,value->languages_count,value->contracts,value->contracts_count,value->tables,value->tables_count\").Where({\"key\": import_info, \"account\": #account_id#, \"ecosystem\": #ecosystem_id#}).Vars(info)\n\n    SetTitle(\"Import - #info_value_app_name#\")\n    Data(data_info, \"DataName,DataCount,DataInfo\"){\n        Pages,\"#info_value_pages_count#\",\"#info_value_pages#\"\n        Blocks,\"#info_value_blocks_count#\",\"#info_value_blocks#\"\n        Menu,\"#info_value_menu_count#\",\"#info_value_menu#\"\n        Parameters,\"#info_value_parameters_count#\",\"#info_value_parameters#\"\n        Language resources,\"#info_value_languages_count#\",\"#info_value_languages#\"\n        Contracts,\"#info_value_contracts_count#\",\"#info_value_contracts#\"\n        Tables,\"#info_value_tables_count#\",\"#info_value_tables#\"\n    }\n    Div(breadcrumb){\n        Span(Class: text-muted, Body: \"Your data that you can import\")\n    }\n\n    Div(panel panel-primary){\n        ForList(data_info){\n            Div(list-group-item){\n                Div(row){\n                    Div(col-md-10 mc-sm text-left){\n                        Span(Class: text-bold, Body: \"#DataName#\")\n                    }\n                    Div(col-md-2 mc-sm text-right){\n                        If(#DataCount# > 0){\n                            Span(Class: text-bold, Body: \"(#DataCount#)\")\n                        }.Else{\n                            Span(Class: text-muted, Body: \"(0)\")\n                        }\n                    }\n                }\n                Div(row){\n                    Div(col-md-12 mc-sm text-left){\n                        If(#DataCount# > 0){\n                            Span(Class: h6, Body: \"#DataInfo#\")\n                        }.Else{\n                            Span(Class: text-muted h6, Body: \"Nothing selected\")\n                        }\n                    }\n                }\n            }\n        }\n        If(#import_id# > 0){\n            Div(list-group-item text-right){\n                VarAsIs(imp_data, \"#import_value_data#\")\n                Button(Body: \"Import\", Class: btn btn-primary, Page: @1apps_list).CompositeContract(@1Import, \"#imp_data#\")\n            }\n        }\n    }\n}', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1'),\n\t(next_id('1_pages'), 'import_upload', 'Div(content-wrapper){\n        SetTitle(\"Import\")\n        Div(breadcrumb){\n            Span(Class: text-muted, Body: \"Select payload that you want to import\")\n        }\n        Form(panel panel-primary){\n            Div(list-group-item){\n                Input(Name: Data, Type: file)\n            }\n            Div(list-group-item text-right){\n                Button(Body: \"Load\", Class: btn btn-primary, Contract: @1ImportUpload, Page: @1import_app)\n            }\n        }\n    }', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1');\n`\n"
  },
  {
    "path": "packages/migration/clb/parameters_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar parametersDataSQL = `\nINSERT INTO \"1_parameters\" (\"id\",\"name\", \"value\", \"conditions\", \"ecosystem\") VALUES\n(next_id('1_parameters'),'founder_account', '%[2]d', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'new_table', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_tables', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_language', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_page', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_menu', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_contracts', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_parameters', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_app_params', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'max_sum', '1000000', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'stylesheet', 'body {\n\t/* You can define your custom styles here or create custom CSS rules */\n}', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'print_stylesheet', 'body {\n\t/* You can define your custom styles here or create custom CSS rules */\n}', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'min_page_validate_count', '1', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'max_page_validate_count', '6', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d'),\n(next_id('1_parameters'),'changing_snippets', 'ContractConditions(\"MainCondition\")', 'ContractConditions(\"@1DeveloperCondition\")', '%[1]d');\n`\n"
  },
  {
    "path": "packages/migration/clb/platform_parameters_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar platformParametersDataSQL = `\nINSERT INTO \"1_platform_parameters\" (\"id\",\"name\", \"value\", \"conditions\") VALUES \n\t(next_id('1_platform_parameters'),'default_ecosystem_page', 'If(#ecosystem_id# > 1){Include(@1welcome)}', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'default_ecosystem_menu', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'default_ecosystem_contract', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'gap_between_blocks', '2', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'rollback_blocks', '60', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'honor_nodes', '', 'ContractAccess(\"@1UpdatePlatformParam\",\"@1NodeRemoveByKey\")'),\n\t(next_id('1_platform_parameters'),'number_of_nodes', '101', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_ecosystem', '2000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_table', '25', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_column', '25', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_contract', '25', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_menu', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_page', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_block_size', '67108864', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_tx_size', '33554432', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_tx_block', '1000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_columns', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_indexes', '5', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_tx_block_per_user', '1000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_fuel_tx', '20000000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_fuel_block', '200000000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'taxes_size', '3', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'taxes_wallet', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'fuel_rate', '[[\"1\",\"1000000\"]]', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_address_to_id', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_id_to_address', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_hash', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_pub_to_id', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_ecosys_param', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_sys_param_string', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_sys_param_int', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_sys_fuel', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_validate_condition', '30', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_eval_condition', '20', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_has_prefix', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_contains', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_replace', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_join', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_update_lang', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_size', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_substr', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_contracts_list', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_is_object', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_compile_contract', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_flush_contract', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_eval', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_len', '5', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_bind_wallet', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_unbind_wallet', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_create_ecosystem', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_table_conditions', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_create_table', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_perm_table', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_column_condition', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_create_column', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_perm_column', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_block_generation_time', '2000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'block_reward','10','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'incorrect_blocks_per_day','10','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'node_ban_time','86400000','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'node_ban_time_local','1800000','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_tx_size', '15', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_rate', '1000000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'test','false','false'),\n\t(next_id('1_platform_parameters'),'price_tx_data', '0', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_contract_by_name', '20', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_exec_contract_by_id', '20', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'private_blockchain', '1', 'false'),\n\t(next_id('1_platform_parameters'),'price_create_application', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'external_blockchain', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'pay_free_contract', '@1CallDelayedContract', 'ContractAccess(\"@1UpdatePlatformParam\")');\n`\n"
  },
  {
    "path": "packages/migration/clb/roles_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nimport \"github.com/IBAX-io/go-ibax/packages/consts\"\n\nvar rolesDataSQL = `\nINSERT INTO \"1_roles\" (\"id\", \"default_page\", \"role_name\", \"deleted\", \"role_type\", \"creator\",\"roles_access\", \"ecosystem\") VALUES\n\t(next_id('1_roles'),'', 'Admin', '0', '3', '{}', '{}', '%[1]d'),\n\t(next_id('1_roles'),'', 'Developer', '0', '3', '{}', '{}', '%[1]d'),\n\t(next_id('1_roles'),'', 'Chain Consensus asbl', '0', '3', '{}', '{\"rids\": \"1\"}', '%[1]d'),\n\t(next_id('1_roles'),'', 'Candidate for validators', '0', '3', '{}', '{}', '%[1]d'),\n\t(next_id('1_roles'),'', 'Validator', '0', '3', '{}', '{}', '%[1]d'),\n\t(next_id('1_roles'),'', 'Investor with voting rights', '0', '3', '{}', '{}', '%[1]d'),\n\t(next_id('1_roles'),'', 'Delegate', '0', '3', '{}', '{}', '%[1]d');\n\n\tINSERT INTO \"1_roles_participants\" (\"id\",\"role\" ,\"member\", \"date_created\", \"ecosystem\")\n\tVALUES (next_id('1_roles_participants'), '{\"id\": \"1\", \"type\": \"3\", \"name\": \"Admin\", \"image_id\":\"0\"}', '{\"member_id\": \"%[2]d\", \"member_name\": \"founder\", \"image_id\": \"0\"}', floor(extract(epoch from now())), '%[1]d'),\n\t(next_id('1_roles_participants'), '{\"id\": \"2\", \"type\": \"3\", \"name\": \"Developer\", \"image_id\":\"0\"}', '{\"member_id\": \"%[2]d\", \"member_name\": \"founder\", \"image_id\": \"0\"}', floor(extract(epoch from now())), '%[1]d');\n\n\tINSERT INTO \"1_members\" (\"id\", \"account\", \"member_name\", \"ecosystem\") \n\tVALUES\n\t\t(next_id('1_members'), '%[3]s', 'founder', '%[1]d'),\n\t\t(next_id('1_members'), '` + consts.GuestAddress + `', 'guest', '%[1]d');\n\n`\n"
  },
  {
    "path": "packages/migration/clb/scheme.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nimport (\n\t\"strings\"\n)\n\n// GetCLBScript returns script to create ecosystem\nfunc GetCLBScript() string {\n\tscripts := []string{\n\t\tschemaCLB,\n\t\tsnippetsDataSQL,\n\t\tcontractsDataSQL,\n\t\tmenuDataSQL,\n\t\tpagesDataSQL,\n\t\tparametersDataSQL,\n\t\trolesDataSQL,\n\t\tsectionsDataSQL,\n\t\ttablesDataSQL,\n\t\tapplicationsDataSQL,\n\t\tkeysDataSQL,\n\t\tplatformParametersDataSQL,\n\t}\n\n\treturn strings.Join(scripts, \"\\r\\n\")\n}\n\n// SchemaEcosystem contains SQL queries for creating ecosystem\nvar schemaCLB = `DROP TABLE IF EXISTS \"1_keys\"; CREATE TABLE \"1_keys\" (\n\t\t\"id\" bigint  NOT NULL DEFAULT '0',\n\t\t\"pub\" bytea  NOT NULL DEFAULT '',\n\t\t\"amount\" decimal(30) NOT NULL DEFAULT '0' CHECK (amount >= 0),\n\t\t\"multi\" bigint NOT NULL DEFAULT '0',\n\t\t\"deleted\" bigint NOT NULL DEFAULT '0',\n\t\t\"blocked\" bigint NOT NULL DEFAULT '0',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1',\n\t\t\"account\" char(24) NOT NULL\n\t\t);\n\t\tALTER TABLE ONLY \"1_keys\" ADD CONSTRAINT \"%[1]d_keys_pkey\" PRIMARY KEY (id,ecosystem);\n\t\t\n\t\tDROP TABLE IF EXISTS \"1_history\"; CREATE TABLE \"1_history\" (\n\t\t\"id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"sender_id\" bigint NOT NULL DEFAULT '0',\n\t\t\"recipient_id\" bigint NOT NULL DEFAULT '0',\n\t\t\"amount\" decimal(30) NOT NULL DEFAULT '0',\n\t\t\"comment\" text NOT NULL DEFAULT '',\n\t\t\"block_id\" int  NOT NULL DEFAULT '0',\n\t\t\"txhash\" bytea  NOT NULL DEFAULT '',\n\t\t\"created_at\" bigint NOT NULL DEFAULT '0',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_history\" ADD CONSTRAINT \"%[1]d_history_pkey\" PRIMARY KEY (id);\n\t\tCREATE INDEX \"%[1]d_history_index_sender\" ON \"%[1]d_history\" (sender_id);\n\t\tCREATE INDEX \"%[1]d_history_index_recipient\" ON \"%[1]d_history\" (recipient_id);\n\t\tCREATE INDEX \"%[1]d_history_index_block\" ON \"%[1]d_history\" (block_id, txhash);\n\t\t\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_languages\"; CREATE TABLE \"%[1]d_languages\" (\n\t\t  \"id\" bigint  NOT NULL DEFAULT '0',\n\t\t  \"name\" character varying(100) NOT NULL DEFAULT '',\n\t\t  \"res\" text NOT NULL DEFAULT '',\n\t\t  \"conditions\" text NOT NULL DEFAULT '',\n\t\t  \"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_languages\" ADD CONSTRAINT \"%[1]d_languages_pkey\" PRIMARY KEY (id);\n\t\tCREATE INDEX \"%[1]d_languages_index_name\" ON \"%[1]d_languages\" (name);\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_sections\"; CREATE TABLE \"%[1]d_sections\" (\n\t\t\"id\" bigint  NOT NULL DEFAULT '0',\n\t\t\"title\" varchar(255)  NOT NULL DEFAULT '',\n\t\t\"urlname\" varchar(255) NOT NULL DEFAULT '',\n\t\t\"page\" varchar(255) NOT NULL DEFAULT '',\n\t\t\"roles_access\" text NOT NULL DEFAULT '',\n\t\t\"delete\" bigint NOT NULL DEFAULT '0',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t  ALTER TABLE ONLY \"%[1]d_sections\" ADD CONSTRAINT \"%[1]d_sections_pkey\" PRIMARY KEY (id);\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_menu\";\n\t\tCREATE TABLE \"%[1]d_menu\" (\n\t\t\t\"id\" bigint  NOT NULL DEFAULT '0',\n\t\t\t\"name\" character varying(255) UNIQUE NOT NULL DEFAULT '',\n\t\t\t\"title\" character varying(255) NOT NULL DEFAULT '',\n\t\t\t\"value\" text NOT NULL DEFAULT '',\n\t\t\t\"conditions\" text NOT NULL DEFAULT '',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_menu\" ADD CONSTRAINT \"%[1]d_menu_pkey\" PRIMARY KEY (id);\n\t\tCREATE INDEX \"%[1]d_menu_index_name\" ON \"%[1]d_menu\" (name);\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_pages\"; \n\t\tCREATE TABLE \"%[1]d_pages\" (\n\t\t\t\"id\" bigint  NOT NULL DEFAULT '0',\n\t\t\t\"name\" character varying(255) UNIQUE NOT NULL DEFAULT '',\n\t\t\t\"value\" text NOT NULL DEFAULT '',\n\t\t\t\"menu\" character varying(255) NOT NULL DEFAULT '',\n\t\t\t\"validate_count\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"conditions\" text NOT NULL DEFAULT '',\n\t\t\t\"app_id\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"validate_mode\" character(1) NOT NULL DEFAULT '0',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_pages\" ADD CONSTRAINT \"%[1]d_pages_pkey\" PRIMARY KEY (id);\n\t\tCREATE INDEX \"%[1]d_pages_index_name\" ON \"%[1]d_pages\" (name);\n\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_blocks\"; CREATE TABLE \"%[1]d_blocks\" (\n\t\t\t\"id\" bigint  NOT NULL DEFAULT '0',\n\t\t\t\"name\" character varying(255) UNIQUE NOT NULL DEFAULT '',\n\t\t\t\"value\" text NOT NULL DEFAULT '',\n\t\t\t\"conditions\" text NOT NULL DEFAULT '',\n\t\t\t\"app_id\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_blocks\" ADD CONSTRAINT \"%[1]d_blocks_pkey\" PRIMARY KEY (id);\n\t\tCREATE INDEX \"%[1]d_blocks_index_name\" ON \"%[1]d_blocks\" (name);\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_signatures\"; CREATE TABLE \"%[1]d_signatures\" (\n\t\t\t\"id\" bigint  NOT NULL DEFAULT '0',\n\t\t\t\"name\" character varying(100) NOT NULL DEFAULT '',\n\t\t\t\"value\" jsonb,\n\t\t\t\"conditions\" text NOT NULL DEFAULT ''\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_signatures\" ADD CONSTRAINT \"%[1]d_signatures_pkey\" PRIMARY KEY (name);\n\t\t\n\t\tCREATE TABLE \"%[1]d_contracts\" (\n\t\t\"id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"name\" text NOT NULL UNIQUE DEFAULT '',\n\t\t\"value\" text  NOT NULL DEFAULT '',\n\t\t\"wallet_id\" bigint NOT NULL DEFAULT '0',\n\t\t\"token_id\" bigint NOT NULL DEFAULT '1',\n\t\t\"conditions\" text  NOT NULL DEFAULT '',\n\t\t\"app_id\" bigint NOT NULL DEFAULT '1',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_contracts\" ADD CONSTRAINT \"%[1]d_contracts_pkey\" PRIMARY KEY (id);\n\t\t\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_parameters\";\n\t\tCREATE TABLE \"%[1]d_parameters\" (\n\t\t\"id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"name\" varchar(255) UNIQUE NOT NULL DEFAULT '',\n\t\t\"value\" text NOT NULL DEFAULT '',\n\t\t\"conditions\" text  NOT NULL DEFAULT '',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_parameters\" ADD CONSTRAINT \"%[1]d_parameters_pkey\" PRIMARY KEY (\"id\");\n\t\tCREATE INDEX \"%[1]d_parameters_index_name\" ON \"%[1]d_parameters\" (name);\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_app_params\";\n\t\tCREATE TABLE \"%[1]d_app_params\" (\n\t\t\"id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"app_id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"name\" varchar(255) UNIQUE NOT NULL DEFAULT '',\n\t\t\"value\" text NOT NULL DEFAULT '',\n\t\t\"conditions\" text  NOT NULL DEFAULT '',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_app_params\" ADD CONSTRAINT \"%[1]d_app_params_pkey\" PRIMARY KEY (\"id\");\n\t\tCREATE INDEX \"%[1]d_app_params_index_name\" ON \"%[1]d_app_params\" (name);\n\t\tCREATE INDEX \"%[1]d_app_params_index_app\" ON \"%[1]d_app_params\" (app_id);\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_tables\";\n\t\tCREATE TABLE \"%[1]d_tables\" (\n\t\t\"id\" bigint NOT NULL  DEFAULT '0',\n\t\t\"name\" varchar(100) UNIQUE NOT NULL DEFAULT '',\n\t\t\"permissions\" jsonb,\n\t\t\"columns\" jsonb,\n\t\t\"conditions\" text  NOT NULL DEFAULT '',\n\t\t\"app_id\" bigint NOT NULL DEFAULT '1',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_tables\" ADD CONSTRAINT \"%[1]d_tables_pkey\" PRIMARY KEY (\"id\");\n\t\tCREATE INDEX \"%[1]d_tables_index_name\" ON \"%[1]d_tables\" (name);\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_notifications\";\n\t\tCREATE TABLE \"%[1]d_notifications\" (\n\t\t\t\"id\"    bigint NOT NULL DEFAULT '0',\n\t\t\t\"recipient\" jsonb,\n\t\t\t\"sender\" jsonb,\n\t\t\t\"notification\" jsonb,\n\t\t\t\"page_params\"\tjsonb,\n\t\t\t\"processing_info\" jsonb,\n\t\t\t\"page_name\"\tvarchar(255) NOT NULL DEFAULT '',\n\t\t\t\"date_created\"\tbigint NOT NULL DEFAULT '0',\n\t\t\t\"date_start_processing\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"date_closed\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"closed\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_notifications\" ADD CONSTRAINT \"%[1]d_notifications_pkey\" PRIMARY KEY (\"id\");\n\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_roles\";\n\t\tCREATE TABLE \"%[1]d_roles\" (\n\t\t\t\"id\" \tbigint NOT NULL DEFAULT '0',\n\t\t\t\"default_page\"\tvarchar(255) NOT NULL DEFAULT '',\n\t\t\t\"role_name\"\tvarchar(255) NOT NULL DEFAULT '',\n\t\t\t\"deleted\"    bigint NOT NULL DEFAULT '0',\n\t\t\t\"role_type\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"creator\" jsonb NOT NULL DEFAULT '{}',\n\t\t\t\"date_created\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"date_deleted\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"company_id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"roles_access\" jsonb, \n\t\t\t\"image_id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_roles\" ADD CONSTRAINT \"%[1]d_roles_pkey\" PRIMARY KEY (\"id\");\n\t\tCREATE INDEX \"%[1]d_roles_index_deleted\" ON \"%[1]d_roles\" (deleted);\n\t\tCREATE INDEX \"%[1]d_roles_index_type\" ON \"%[1]d_roles\" (role_type);\n\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_roles_participants\";\n\t\tCREATE TABLE \"%[1]d_roles_participants\" (\n\t\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"role\" jsonb,\n\t\t\t\"member\" jsonb,\n\t\t\t\"appointed\" jsonb,\n\t\t\t\"date_created\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"date_deleted\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"deleted\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_roles_participants\" ADD CONSTRAINT \"%[1]d_roles_participants_pkey\" PRIMARY KEY (\"id\");\n\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_members\";\n\t\tCREATE TABLE \"%[1]d_members\" (\n\t\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"member_name\"\tvarchar(255) NOT NULL DEFAULT '',\n\t\t\t\"image_id\"\tbigint NOT NULL DEFAULT '0',\n\t\t\t\"member_info\"   jsonb,\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"account\" char(24) NOT NULL\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_members\" ADD CONSTRAINT \"%[1]d_members_pkey\" PRIMARY KEY (\"id\");\n\t\tCREATE INDEX \"%[1]d_members_index_ecosystem\" ON \"1_sections\" (ecosystem);\n\t\tCREATE UNIQUE INDEX \"%[1]d_members_uindex_ecosystem_account\" ON \"1_members\" (account, ecosystem);\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_applications\";\n\t\tCREATE TABLE \"%[1]d_applications\" (\n\t\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"name\" varchar(255) NOT NULL DEFAULT '',\n\t\t\t\"uuid\" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',\n\t\t\t\"conditions\" text NOT NULL DEFAULT '',\n\t\t\t\"deleted\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_applications\" ADD CONSTRAINT \"%[1]d_application_pkey\" PRIMARY KEY (\"id\");\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_binaries\";\n\t\tCREATE TABLE \"%[1]d_binaries\" (\n\t\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"app_id\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"name\" varchar(255) NOT NULL DEFAULT '',\n\t\t\t\"data\" bytea NOT NULL DEFAULT '',\n\t\t\t\"hash\" varchar(32) NOT NULL DEFAULT '',\n\t\t\t\"mime_type\" varchar(255) NOT NULL DEFAULT '',\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"account\" char(24) NOT NULL\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_binaries\" ADD CONSTRAINT \"%[1]d_binaries_pkey\" PRIMARY KEY (id);\n\t\tCREATE UNIQUE INDEX \"%[1]d_binaries_uindex\" ON \"%[1]d_binaries\" (account, ecosystem, app_id, name);\n\t\t\n\t\tDROP TABLE IF EXISTS \"%[1]d_buffer_data\";\n\t\tCREATE TABLE \"%[1]d_buffer_data\" (\n\t\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\"key\" varchar(255) NOT NULL DEFAULT '',\n\t\t\t\"value\" jsonb,\n\t\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1',\n\t\t\t\"account\" char(24) NOT NULL\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_buffer_data\" ADD CONSTRAINT \"%[1]d_buffer_data_pkey\" PRIMARY KEY (\"id\");\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_platform_parameters\";\n\t\tCREATE TABLE \"%[1]d_platform_parameters\" (\n\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\"name\" varchar(255)  NOT NULL DEFAULT '',\n\t\t\"value\" text NOT NULL DEFAULT '',\n\t\t\"conditions\" text  NOT NULL DEFAULT '',\n\t\t\"ecosystem\" bigint NOT NULL DEFAULT '1'\n\t\t);\n\t\tALTER TABLE ONLY \"%[1]d_platform_parameters\" ADD CONSTRAINT \"%[1]d_platform_parameters_pkey\" PRIMARY KEY (id);\n\t\tCREATE INDEX \"%[1]d_platform_parameters_index_name\" ON \"%[1]d_platform_parameters\" (name);\n\n\t\tDROP TABLE IF EXISTS \"%[1]d_cron\";\n\t  CREATE TABLE \"%[1]d_cron\" (\n\t\t  \"id\"        bigint NOT NULL DEFAULT '0',\n\t\t  \"owner\"\t  bigint NOT NULL DEFAULT '0',\n\t\t  \"cron\"      varchar(255) NOT NULL DEFAULT '',\n\t\t  \"contract\"  varchar(255) NOT NULL DEFAULT '',\n\t\t  \"counter\"   bigint NOT NULL DEFAULT '0',\n\t\t  \"till\"      timestamp NOT NULL DEFAULT timestamp '1970-01-01 00:00:00',\n\t\t  \"conditions\" text  NOT NULL DEFAULT ''\n\t  );\n\t  ALTER TABLE ONLY \"%[1]d_cron\" ADD CONSTRAINT \"%[1]d_cron_pkey\" PRIMARY KEY (\"id\");\n\t\n`\n"
  },
  {
    "path": "packages/migration/clb/sections_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar sectionsDataSQL = `\nINSERT INTO \"1_sections\" (\"id\",\"title\",\"urlname\",\"page\",\"roles_access\", \"delete\", \"ecosystem\") VALUES\n('1', 'Home', 'home', 'default_page', '', 0, '%[1]d');`\n"
  },
  {
    "path": "packages/migration/clb/snippets_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar snippetsDataSQL = `INSERT INTO \"1_snippets\" (id, name, value, conditions, app_id, ecosystem) VALUES\n\t\t(next_id('1_snippets'), 'pager_header', '', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1');\n`\n"
  },
  {
    "path": "packages/migration/clb/tables_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage clb\n\nvar tablesDataSQL = `INSERT INTO \"1_tables\" (\"id\", \"name\", \"permissions\",\"columns\", \"conditions\") VALUES \n(next_id('1_tables'), 'contracts', '{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}', \n'{\"name\": \"false\", \n\t\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"wallet_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"token_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"}', 'ContractAccess(\"@1EditTable\")'),\n\t(next_id('1_tables'), 'keys', \n\t'{\"insert\": \"true\", \"update\": \"true\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\n\t\t\"pub\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"amount\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"deleted\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"blocked\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"multi\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"account\": \"false\",\n\t\t\"ecosystem\": \"false\",\n\t\t\"multi\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n\t}', \n\t'ContractAccess(\"@1EditTable\")'),\n\t(next_id('1_tables'), 'history', \n\t'{\"insert\": \"ContractConditions(\\\"NodeOwnerCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\"sender_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"recipient_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"amount\":  \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"comment\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"block_id\":  \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"txhash\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"created_at\": \"false\"}', 'ContractAccess(\"@1EditTable\")'),        \n\t(next_id('1_tables'), 'languages', \n\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\"app_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"res\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"conditions\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"app_id\": \"ContractConditions(\\\"MainCondition\\\")\"}', 'ContractAccess(\"@1EditTable\")'),\n\t(next_id('1_tables'), 'menu', \n\t\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"\n\t}', 'ContractAccess(\"@1EditTable\")'),\n\t(next_id('1_tables'), 'pages', \n\t\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"menu\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"validate_count\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"validate_mode\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"app_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"\n\t}', 'ContractAccess(\"@1EditTable\")'),\n\t(next_id('1_tables'), 'blocks', \n\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"\n\t}', 'ContractAccess(\"@1EditTable\")'),\n\t('8', 'signatures', \n\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t  \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t'{\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"\n\t}', 'ContractAccess(\"@1EditTable\")'),\n\t('9', 'members', \n\t\t'{\"insert\":\"ContractAccess(\\\"Profile_Edit\\\")\",\"update\":\"ContractConditions(\\\"MainCondition\\\")\",\"new_column\":\"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\n\t\t\t\"image_id\":\"ContractAccess(\\\"Profile_Edit\\\")\",\n\t\t\t\"member_info\":\"ContractAccess(\\\"Profile_Edit\\\")\",\n\t\t\t\"member_name\":\"false\",\n\t\t\t\"account\":\"false\"\n\t\t}', \n\t\t'ContractConditions(\"MainCondition\")'),\n\t('10', 'roles',\n\t\t'{\"insert\":\"ContractAccess(\\\"Roles_Create\\\")\",\n\t\t\t\"update\":\"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"new_column\":\"ContractConditions(\\\"MainCondition\\\")\"}', \n\t\t'{\"default_page\":\"false\",\n\t\t\t\"creator\":\"false\",\n\t\t\t\"deleted\":\"ContractAccess(\\\"Roles_Del\\\")\",\n\t\t\t\"company_id\":\"false\",\n\t\t\t\"date_deleted\":\"ContractAccess(\\\"Roles_Del\\\")\",\n\t\t\t\"image_id\":\"ContractAccess(\\\"Roles_Create\\\")\",\n\t\t\t\"role_name\":\"false\",\n\t\t\t\"date_created\":\"false\",\n\t\t\t\"roles_access\":\"ContractAccess(\\\"Roles_AccessManager\\\")\",\n\t\t\t\"role_type\":\"false\"}',\n\t\t'ContractConditions(\"MainCondition\")'),\n\t('11', 'roles_participants',\n\t\t'{\"insert\":\"ContractAccess(\\\"Roles_Assign\\\",\\\"voting_CheckDecision\\\")\",\n\t\t\t\"update\":\"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"new_column\":\"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\"deleted\":\"ContractAccess(\\\"Roles_Unassign\\\")\",\n\t\t\t\"date_deleted\":\"ContractAccess(\\\"Roles_Unassign\\\")\",\n\t\t\t\"member\":\"false\",\n\t\t\t\"role\":\"false\",\n\t\t\t\"date_created\":\"false\",\n\t\t\t\"appointed\":\"false\"}', \n\t\t'ContractConditions(\"MainCondition\")'),\n\t('12', 'notifications',\n\t\t'{\"insert\":\"ContractAccess(\\\"notifications_Send\\\", \\\"CheckNodesBan\\\")\",\n\t\t\t\"update\":\"ContractAccess(\\\"notifications_Send\\\", \\\"notifications_Close\\\", \\\"notifications_Process\\\")\",\n\t\t\t\"new_column\":\"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\"date_closed\":\"ContractAccess(\\\"notifications_Close\\\")\",\n\t\t\t\"sender\":\"false\",\n\t\t\t\"processing_info\":\"ContractAccess(\\\"notifications_Close\\\",\\\"notifications_Process\\\")\",\n\t\t\t\"date_start_processing\":\"ContractAccess(\\\"notifications_Close\\\",\\\"notifications_Process\\\")\",\n\t\t\t\"notification\":\"false\",\n\t\t\t\"page_name\":\"false\",\n\t\t\t\"page_params\":\"false\",\n\t\t\t\"closed\":\"ContractAccess(\\\"notifications_Close\\\")\",\n\t\t\t\"date_created\":\"false\",\n\t\t\t\"recipient\":\"false\"}',\n\t\t'ContractAccess(\"@1EditTable\")'),\n\t('13', 'sections', \n\t\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t\t\"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\"title\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"urlname\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"page\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"roles_access\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"delete\": \"ContractConditions(\\\"MainCondition\\\")\"}', \n\t\t\t'ContractConditions(\"MainCondition\")'),\n\t('14', 'applications',\n\t\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t \"update\": \"ContractConditions(\\\"MainCondition\\\")\", \n\t\t\t \"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t  \"uuid\": \"false\",\n\t\t  \"conditions\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t  \"deleted\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'ContractConditions(\"MainCondition\")'),\n\t('15', 'binaries',\n\t\t'{\"insert\":\"ContractAccess(\\\"@1UploadBinary\\\")\",\n\t\t\t\"update\":\"ContractAccess(\\\"@1UploadBinary\\\")\",\n\t\t\t\"new_column\":\"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\n\t\t\t\"hash\":\"ContractAccess(\\\"@1UploadBinary\\\")\",\n\t\t\t\"account\": \"false\",\n\t\t\t\"data\":\"ContractAccess(\\\"@1UploadBinary\\\")\",\n\t\t\t\"name\":\"false\",\n\t\t\t\"app_id\":\"false\",\n\t\t\t\"mime_type\": \"ContractAccess(\\\"@1UploadBinary\\\")\"\n\t\t}',\n\t\t'ContractConditions(\\\"MainCondition\\\")'),\n\t('16', 'parameters',\n\t\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'ContractAccess(\"@1EditTable\")'),\n\t('17', 'app_params',\n\t\t'{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\"app_id\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"name\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"value\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'ContractAccess(\"@1EditTable\")'),\n\t\t('18', 'cron',\n\t  '{\"insert\": \"ContractConditions(\\\"MainCondition\\\")\", \"update\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"new_column\": \"ContractConditions(\\\"MainCondition\\\")\"}',\n\t  '{\"owner\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"cron\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"contract\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"counter\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t  \"till\": \"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\"conditions\": \"ContractConditions(\\\"MainCondition\\\")\"\n\t  }', 'ContractConditions(\"MainCondition\")'),\n\t('19', 'buffer_data',\n\t\t'{\"insert\":\"true\",\"update\":\"ContractConditions(\\\"MainCondition\\\")\",\n\t\t\t\"new_column\":\"ContractConditions(\\\"MainCondition\\\")\"}',\n\t\t'{\n\t\t\t\"key\": \"false\",\n\t\t\t\"value\": \"true\",\n\t\t\t\"account\": \"false\"\n\t\t}',\n\t\t'ContractConditions(\"MainCondition\")');\n`\n"
  },
  {
    "path": "packages/migration/contracts/clb/EditCron.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditCron {\n\t\tdata {\n\t\t\tId         int\n\t\t\tContract   string\n\t\t\tCron       string \"optional\"\n\t\t\tLimit      int \"optional\"\n\t\t\tTill       string \"optional date\"\n\t\t\tConditions string\n\t\t}\n\t\tconditions {\n\t\t\tConditionById(\"cron\", true)\n\t\t\tValidateCron($Cron)\n\t\t}\n\t\taction {\n\t\t\tif !$Till {\n\t\t\t\t$Till = \"1970-01-01 00:00:00\"\n\t\t\t}\n\t\t\tif !HasPrefix($Contract, \"@\") {\n\t\t\t\t$Contract = \"@\" + Str($ecosystem_id) + $Contract\n\t\t\t}\n\t\t\tDBUpdate(\"cron\", $Id, {\"cron\": $Cron,\"contract\": $Contract,\n\t\t\t    \"counter\":$Limit, \"till\": $Till, \"conditions\":$Conditions})\n\t\t\tUpdateCron($Id)\n\t\t}\n\t}"
  },
  {
    "path": "packages/migration/contracts/clb/ListCLB.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract ListCLB {\n\t\tdata {}\n\t\n\t\tconditions {}\n\t\n\t\taction {\n\t\t\t$result = GetCLBList()\n\t\t}\n\t}"
  },
  {
    "path": "packages/migration/contracts/clb/MainCondition.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract MainCondition {\n\t\tconditions {\n\t\t  if EcosysParam(\"founder_account\")!=$key_id\n\t\t  {\n\t\t\twarning \"Sorry, you do not have access to this action.\"\n\t\t  }\n\t\t}\n\t  }"
  },
  {
    "path": "packages/migration/contracts/clb/NewCLB.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewCLB {\n\t\tdata {\n\t\t\tCLBName string\n\t\t\tDBUser string\n\t\t\tDBPassword string\n\t\t\tCLBAPIPort int\n\t\t}\n\t\n\t\tconditions {\n            if Size($CLBName) == 0 {\n                warning \"CLBName was not received\"\n            }\n            if Contains($CLBName, \" \") {\n                error \"CLBName can not contain spaces\"\n            }\n            if Size($DBUser) == 0 {\n                warning \"DBUser was not received\"\n            }\n            if Size($DBPassword) == 0 {\n                warning \"DBPassword was not received\"\n            }\n            if $CLBAPIPort <= 0  {\n                warning \"CLB API PORT not received\"\n            }\n            \n\t\t}\n\t\n\t\taction {\n            $CLBName = ToLower($CLBName)\n            $DBUser = ToLower($DBUser)\n            CreateCLB($CLBName, $DBUser, $DBPassword, $CLBAPIPort)\n            $result = \"CLB \" + $CLBName + \" created\"\n\t\t}\n}"
  },
  {
    "path": "packages/migration/contracts/clb/NewCron.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewCron {\n\t\tdata {\n\t\t\tCron       string\n\t\t\tContract   string\n\t\t\tLimit      int \"optional\"\n\t\t\tTill       string \"optional date\"\n\t\t\tConditions string\n\t\t}\n\t\tconditions {\n\t\t\tValidateCondition($Conditions,$ecosystem_id)\n\t\t\tValidateCron($Cron)\n\t\t}\n\t\taction {\n\t\t\tif !$Till {\n\t\t\t\t$Till = \"1970-01-01 00:00:00\"\n\t\t\t}\n\t\t\tif !HasPrefix($Contract, \"@\") {\n\t\t\t\t$Contract = \"@\" + Str($ecosystem_id) + $Contract\n\t\t\t}\n\t\t\t$result = DBInsert(\"cron\", {owner: $key_id,cron:$Cron,contract: $Contract,\n\t\t\t\tcounter:$Limit, till: $Till,conditions: $Conditions})\n\t\t\tUpdateCron($result)\n\t\t}\n\t}"
  },
  {
    "path": "packages/migration/contracts/clb/RemoveCLB.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract RemoveCLB {\n\tdata {\n\t\t\tCLBName string\n\t}\n\tconditions {}\n\taction{\n        $CLBName = ToLower($CLBName)\n        DeleteCLB($CLBName)\n        $result = \"CLB \" + $CLBName + \" removed\"\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/clb/RunCLB.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract RunCLB {\n\tdata {\n\t\tCLBName string\n\t}\t\n\tconditions {\n\t}\t\n\taction {\n\t\t$CLBName = ToLower($CLBName)\n\t\tStartCLB($CLBName)\n\t\t$result = \"CLB \" + $CLBName + \" running\"\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/clb/StopCLB.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract StopCLB {\n\t\tdata {\n\t\t\tCLBName string\n\t\t}\n\t\n\t\tconditions {\n\t\t}\n\t\n\t\taction {\n\t\t\t$CLBName = ToLower($CLBName)\n\t\t\tStopCLBProcess($CLBName)\n\t\t\t$result = \"CLB \" + $CLBName + \" stopped\"\n\t\t}\n}"
  },
  {
    "path": "packages/migration/contracts/ecosystem/DeveloperCondition.sim",
    "content": "// +prop AppID = '{{.AppID}}'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\n// This contract is used to set \"developer\" rights.\n// Usually the \"developer\" role is used for this.\n// The role ID is written to the ecosystem parameter and can be changed.\n// The contract requests the role ID from the ecosystem parameter and the contract checks the rights.\n\ncontract DeveloperCondition {\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n    }\n    conditions {\n        chooseControl()\n        if $control[\"control_mode\"] == 2{\n            return\n        }\n        // check for Founder\n        if EcosysParam(\"founder_account\") == AddressToId($account_id) {\n            return\n        }\n        // check for Developer role\n        var app_id int role_id string\n        app_id = Int(DBFind(\"@1applications\").Where({\"ecosystem\": $ecosystem_id, \"name\": \"System\"}).One(\"id\"))\n        role_id = AppParam(app_id, \"role_developer\", $ecosystem_id)\n\n        if Size(role_id) == 0 {\n            warning Sprintf(LangRes(\"@1x_not_access_action\"),\"DeveloperCondition\")\n        }\n        if !RoleAccess(Int(role_id)) {\n            warning Sprintf(LangRes(\"@1x_not_access_action\"),\"DeveloperCondition\")\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/ecosystem/MainCondition.sim",
    "content": "// +prop AppID = '{{.AppID}}'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract MainCondition {\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n    }\n\tconditions {\n\t    chooseControl()\n        if $control[\"control_mode\"] == 2{\n            return\n        }\n\t\tif EcosysParam(\"founder_account\")!=$key_id\n\t\t{\n\t\t\twarning \"MainCondition: Sorry, you do not have access to this action.\"\n\t\t}\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/AccessControlMode.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract AccessControlMode {\n    data {\n        VotingId int \"optional\"\n    }\n\n    func decentralizedAutonomous(){\n        if !DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":2}).Row(){\n            warning \"control mode DAO error\"\n        }\n        var prev string\n        prev = $stack[0]\n        if Len($stack) > 3{\n            prev = $stack[Len($stack) - 3]\n        }\n        if prev != \"@1VotingDecisionCheck\" {\n            warning LangRes(\"@1contract_start_votingdecisioncheck_only\")\n        }\n\n        $voting = DBFind(\"@1votings\").Where({\"ecosystem\": $ecosystem_id, \"id\": $VotingId,\"voting->name\":{\"$begin\":\"voting_for_control_mode_template\"}}).Columns(\"voting->type_decision,flags->success,voting->type\").Row()\n        if Int($voting[\"voting.type\"]) != 2 {\n            warning LangRes(\"@1voting_type_invalid\")\n        }\n        if Int($voting[\"voting.type_decision\"]) != 4 {\n            warning LangRes(\"@1voting_error_decision\")\n        }\n        if Int($voting[\"flags.success\"]) != 1 {\n            warning LangRes(\"@1voting_error_success\")\n        }\n    }\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n\n        if $control[\"control_mode\"] == 2 && $VotingId{\n            decentralizedAutonomous()\n            return\n        }\n        DeveloperCondition()\n    }\n    conditions {\n        $VotingId = Int($VotingId)\n        chooseControl()\n        $result = $control[\"control_mode\"]\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/AccessVoteTempRun.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract AccessVoteTempRun {\n    data {\n        ContractAccept string \"optional\"\n        ContractAcceptParams map \"optional\"\n    }\n\n    func votingCheck(){\n        var app_id int\n        app_id = Int(DBFind(\"@1applications\").Where({\"ecosystem\": $ecosystem_id, \"name\": \"Basic\"}).One(\"id\"))\n        $templateId = Int(DBFind(\"@1app_params\").Where({\"app_id\": app_id, \"name\": \"voting_template_control_mode\", \"ecosystem\": $ecosystem_id}).One(\"value\"))\n        if $templateId == 0 {\n            warning LangRes(\"@1template_id_not_found\")\n        }\n    }\n\n    action {\n        votingCheck()\n        var temp map\n        temp[\"TemplateId\"] = $templateId\n        temp[\"Duration\"] = 7\n        temp[\"ContractAccept\"] = $ContractAccept\n        temp[\"ContractAcceptParams\"] = JSONEncode($ContractAcceptParams)\n        CallContract(\"@1VotingTemplateRun\",temp)\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/BindWallet.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract BindWallet {\n\tdata {\n\t\tId  int\n\t}\n\tconditions {\n\t\t$cur = DBRow(\"contracts\").Columns(\"id,conditions,wallet_id\").WhereId($Id)\n\t\tif !$cur {\n\t\t\terror Sprintf(\"Contract %d does not exist\", $Id)\n\t\t}\n\t\tEval($cur[\"conditions\"])\n\t\tif $key_id != Int($cur[\"wallet_id\"]) {\n\t\t\terror Sprintf(\"Wallet %d cannot activate the contract\", $key_id)\n\t\t}\n\t}\n\taction {\n\t\tBndWallet($Id, $ecosystem_id)\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/CallDelayedContract.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract CallDelayedContract {\n\tdata {\n        Id int\n\t}\n\n\tconditions {\n\t\tHonorNodeCondition()\n\n\t\tvar rows array\n\t\trows = DBFind(\"@1delayed_contracts\").Where({\"id\": $Id, \"deleted\": 0})\n\n\t\tif !Len(rows) {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_not_exist\"), $Id)\n\t\t}\n\t\t$cur = rows[0]\n\t\t$limit = Int($cur[\"limit\"])\n\t\t$counter = Int($cur[\"counter\"])\n\n\t\tif $block < Int($cur[\"block_id\"]) {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_error\"), $Id, $cur[\"block_id\"], $block)\n\t\t}\n\n\t\tif $limit > 0 && $counter >= $limit {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_limited\"), $Id)\n\t\t}\n\t}\n\n\taction {\n\t\t$counter = $counter + 1\n\n\t\tvar block_id int\n\t\tblock_id = $block\n\t\tif $limit == 0 || $limit > $counter {\n\t\t\tblock_id = block_id + Int($cur[\"every_block\"])\n\t\t}\n\n\t\tDBUpdate(\"@1delayed_contracts\", $Id, {\"counter\": $counter, \"block_id\": block_id})\n\n\t\tvar params map\n\t\tCallContract($cur[\"contract\"], params)\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/CheckNodesBan.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract CheckNodesBan {\n    func getPermission() {\n        var array_permissions array result i int prevContract string\n        array_permissions = [\"@1CheckNodesBan\"]\n\n        prevContract = $stack[0]\n        if Len($stack) > 2 {\n            prevContract = $stack[Len($stack) - 2]\n        }\n        while i < Len(array_permissions) {\n            var contract_name string\n            contract_name = array_permissions[i]\n            if contract_name == prevContract {\n                result = 1\n            }\n            i = i + 1\n        }\n\n        if result == 0 {\n            warning LangRes(\"@1contract_chain_distorted\")\n        }\n    }\n    conditions {\n        getPermission()\n        HonorNodeCondition()\n        var rows array\n        rows = DBFind(\"@1delayed_contracts\").Where({\"contract\": \"@1CheckNodesBan\", \"deleted\": 0})\n        if !Len(rows) {\n            warning Sprintf(LangRes(\"@1template_delayed_contract_not_exist\"), $Id)\n        }\n        $cur = rows[0]\n        $counter = Int($cur[\"counter\"]) + 1\n        $Id = Int($cur[\"id\"])\n    }\n    action {\n        DBUpdateExt(\"@1delayed_contracts\", {\"id\":$Id}, {\"counter\": $counter})\n\n        UpdateNodesBan($block_time)\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditAppParam.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditAppParam {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"app_params\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"app_params\", $Id, pars)\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditApplication.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditApplication {\n    data {\n        ApplicationId int\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && false\n    }\n\n    conditions {\n        RowConditions(\"applications\", $ApplicationId, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"applications\", $ApplicationId, pars)\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditColumn.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditColumn {\n    data {\n        TableName string\n        Name string\n        Permissions string\n    }\n\n    conditions {\n        ColumnCondition($TableName, $Name, \"\", $Permissions)\n    }\n\n    action {\n        PermColumn($TableName, $Name, $Permissions)\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditContract.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditContract {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"contracts\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        $cur = DBFind(\"contracts\").Columns(\"id,value,conditions,wallet_id,token_id\").WhereId($Id).Row()\n        if !$cur {\n            error Sprintf(\"Contract %d does not exist\", $Id)\n        }\n        if $Value {\n            ValidateEditContractNewValue($Value, $cur[\"value\"])\n        }\n   \n        $recipient = Int($cur[\"wallet_id\"])\n    }\n\n    action {\n        UpdateContract($Id, $Value, $Conditions, $recipient, $cur[\"token_id\"])\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditLang.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditLang {\n    data {\n        Id int\n        Trans string\n    }\n\n    conditions {\n        EvalCondition(\"parameters\", \"changing_language\", \"value\")\n        $lang = DBFind(\"languages\").Where({id: $Id}).Row()\n    }\n\n    action {\n        EditLanguage($Id, $lang[\"name\"], $Trans)\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditMenu.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditMenu {\n    data {\n        Id int\n        Value string \"optional\"\n        Title string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value && !$Title\n    }\n\n    conditions {\n        RowConditions(\"menu\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Title {\n            pars[\"title\"] = $Title\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"menu\", $Id, pars)\n        }            \n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditPage.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditPage {\n    data {\n        Id int\n        Value string \"optional\"\n        Menu string \"optional\"\n        Conditions string \"optional\"\n        ValidateCount int \"optional\"\n        ValidateMode string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value && !$Menu && !$ValidateCount \n    }\n    func preparePageValidateCount(count int) int {\n        var min, max int\n        min = Int(EcosysParam(\"min_page_validate_count\"))\n        max = Int(EcosysParam(\"max_page_validate_count\"))\n        if count < min {\n            count = min\n        } else {\n            if count > max {\n                count = max\n            }\n        }\n        return count\n    }\n\n    conditions {\n        RowConditions(\"pages\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        $ValidateCount = preparePageValidateCount($ValidateCount)\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Menu {\n            pars[\"menu\"] = $Menu\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if $ValidateCount {\n            pars[\"validate_count\"] = $ValidateCount\n        }\n        if $ValidateMode {\n            if $ValidateMode != \"1\" {\n                $ValidateMode = \"0\"\n            }\n            pars[\"validate_mode\"] = $ValidateMode\n        }\n        if pars {\n            DBUpdate(\"pages\", $Id, pars)\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditParameter.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditParameter {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        DeveloperCondition()\n\n        RowConditions(\"@1parameters\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        if $Value {\n            $Name = DBFind(\"@1parameters\").Where({\"id\": $Id, \"ecosystem\": $ecosystem_id}).One(\"name\")\n            if $Name == \"founder_account\" {\n                var account string\n                account = IdToAddress(Int($Value))\n                if !DBFind(\"@1keys\").Where({\"account\": account, \"ecosystem\": $ecosystem_id, \"deleted\": 0}).One(\"id\") {\n                    warning Sprintf(LangRes(\"@1template_user_not_found\"), $Value)\n                }\n            }\n            if $Name == \"max_block_user_tx\" || $Name == \"money_digit\" || $Name == \"max_sum\" || $Name == \"min_page_validate_count\" || $Name == \"max_page_validate_count\" {\n                if Size($Value) == 0 {\n                    warning LangRes(\"@1value_not_received\")\n                }\n                if Int($Value) <= 0 {\n                    warning LangRes(\"@1value_must_greater_zero\")\n                }\n            }\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            if $Value == `\"\"` {\n                pars[\"value\"] = \"\"\n            } else {\n                pars[\"value\"] = $Value\n            }\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"@1parameters\", $Id, pars)\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditSnippet.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditSnippet {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"snippets\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"snippets\", $Id, pars)\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/EditTable.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract EditTable {\n    data {\n        Name string\n        InsertPerm string\n        UpdatePerm string\n        NewColumnPerm string\n        ReadPerm string \"optional\"\n    }\n\n    conditions {\n        if !$InsertPerm {\n            info(\"Insert condition is empty\")\n        }\n        if !$UpdatePerm {\n            info(\"Update condition is empty\")\n        }\n        if !$NewColumnPerm {\n            info(\"New column condition is empty\")\n        }\n\n        var permissions map\n        permissions[\"insert\"] = $InsertPerm\n        permissions[\"update\"] = $UpdatePerm\n        permissions[\"new_column\"] = $NewColumnPerm\n        if $ReadPerm {\n            permissions[\"read\"] = $ReadPerm\n        }\n        $Permissions = permissions\n        TableConditions($Name, \"\", JSONEncode($Permissions))\n    }\n\n    action {\n        PermTable($Name, JSONEncode($Permissions))\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/HonorNodeCondition.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract HonorNodeCondition {\n\tconditions {\n\t\tvar account_key int\n\t\taccount_key = AddressToId($account_id)\n\t\tif IsHonorNodeKey(account_key) {\n\t\t\treturn\n\t\t}\n\t\twarning \"HonorNodeCondition: Sorry, you do not have access to this action\"\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/Import.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract Import {\n    data {\n        Data string\n    }\n    conditions {\n        $ApplicationId = 0\n        var app_map map\n        app_map = DBFind(\"@1buffer_data\").Columns(\"value->app_name\").Where({\"key\": \"import_info\", \"account\": $account_id, \"ecosystem\": $ecosystem_id}).Row()\n        if app_map {\n            var app_id int ival string\n            ival = Str(app_map[\"value.app_name\"])\n            app_id = Int(DBFind(\"@1applications\").Columns(\"id\").Where({\"name\": ival, \"ecosystem\": $ecosystem_id}).One(\"id\"))\n            if app_id {\n                $ApplicationId = app_id\n            }\n        }\n    }\n    action {\n        var editors, creators map\n        editors[\"pages\"] = \"EditPage\"\n        editors[\"snippets\"] = \"EditSnippet\"\n        editors[\"menu\"] = \"EditMenu\"\n        editors[\"app_params\"] = \"EditAppParam\"\n        editors[\"languages\"] = \"EditLang\"\n        editors[\"contracts\"] = \"EditContract\"\n        editors[\"tables\"] = \"\" // nothing\n        creators[\"pages\"] = \"NewPage\"\n        creators[\"snippets\"] = \"NewSnippet\"\n        creators[\"menu\"] = \"NewMenu\"\n        creators[\"app_params\"] = \"NewAppParam\"\n        creators[\"languages\"] = \"NewLang\"\n        creators[\"contracts\"] = \"NewContract\"\n        creators[\"tables\"] = \"NewTable\"\n        var dataImport array\n        dataImport = JSONDecode($Data)\n        var i int\n        while i < Len(dataImport) {\n            var item cdata map type name string\n            cdata = dataImport[i]\n            if cdata {\n                cdata[\"ApplicationId\"] = $ApplicationId\n                type = cdata[\"Type\"]\n                name = cdata[\"Name\"]\n                // Println(Sprintf(\"import %v: %v\", type, cdata[\"Name\"]))\n                var tbl string\n                tbl = \"@1\" + Str(type)\n                if type == \"app_params\" {\n                    item = DBFind(tbl).Where({\"name\": name, \"ecosystem\": $ecosystem_id, \"app_id\": $ApplicationId}).Row()\n                } else {\n                    item = DBFind(tbl).Where({\"name\": name, \"ecosystem\": $ecosystem_id}).Row()\n                }\n                var contractName string\n                if item {\n                    contractName = editors[type]\n                    cdata[\"Id\"] = Int(item[\"id\"])\n                    if type == \"contracts\" {\n                        if item[\"conditions\"] == \"false\" {\n                            // ignore updating impossible\n                            contractName = \"\"\n                        }\n                    } elif type == \"menu\" {\n                        var menu menuItem string\n                        menu = Replace(item[\"value\"], \" \", \"\")\n                        menu = Replace(menu, \"\\n\", \"\")\n                        menu = Replace(menu, \"\\r\", \"\")\n                        menuItem = Replace(cdata[\"Value\"], \" \", \"\")\n                        menuItem = Replace(menuItem, \"\\n\", \"\")\n                        menuItem = Replace(menuItem, \"\\r\", \"\")\n                        if Contains(menu, menuItem) {\n                            // ignore repeated\n                            contractName = \"\"\n                        } else {\n                            cdata[\"Value\"] = item[\"value\"] + \"\\n\" + cdata[\"Value\"]\n                        }\n                    }\n                } else {\n                    contractName = creators[type]\n                }\n                if contractName != \"\" {\n                    CallContract(contractName, cdata)\n                }\n            }\n            i = i + 1\n        }\n        // Println(Sprintf(\"> time: %v\", $time))\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/ImportUpload.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract ImportUpload {\n    data {\n        Data file\n    }\n    conditions {\n        $Body = BytesToString($Data[\"Body\"])\n        $limit = 10 // data piece size of import\n    }\n    action {\n        // init buffer_data, cleaning old buffer\n        var initJson map\n        $import_id = Int(DBFind(\"@1buffer_data\").Where({\"account\": $account_id, \"key\": \"import\", \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $import_id {\n             DBUpdate(\"@1buffer_data\", $import_id, {\"value\": initJson})\n        } else {\n            $import_id = DBInsert(\"@1buffer_data\", {\"account\": $account_id, \"key\": \"import\", \"value\": initJson, \"ecosystem\": $ecosystem_id})\n        }\n        $info_id = Int(DBFind(\"@1buffer_data\").Where({\"account\": $account_id, \"key\": \"import_info\", \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $info_id {\n            DBUpdate(\"@1buffer_data\", $info_id, {\"value\": initJson})\n        } else {\n            $info_id = DBInsert(\"@1buffer_data\", {\"account\": $account_id, \"key\": \"import_info\", \"value\": initJson, \"ecosystem\": $ecosystem_id})\n        }\n        var input map arrData array\n        input = JSONDecode($Body)\n        arrData = input[\"data\"]\n        var pages_arr blocks_arr menu_arr parameters_arr languages_arr contracts_arr tables_arr array\n        // IMPORT INFO\n        var i lenArrData int item map\n        lenArrData = Len(arrData)\n        while i < lenArrData {\n            item = arrData[i]\n            if item[\"Type\"] == \"pages\" {\n                pages_arr = Append(pages_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"snippets\" {\n                blocks_arr = Append(blocks_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"menu\" {\n                menu_arr = Append(menu_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"app_params\" {\n                parameters_arr = Append(parameters_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"languages\" {\n                languages_arr = Append(languages_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"contracts\" {\n                contracts_arr = Append(contracts_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"tables\" {\n                tables_arr = Append(tables_arr, item[\"Name\"])\n            }\n            i = i + 1\n        }\n        var inf map\n        inf[\"app_name\"] = input[\"name\"]\n        inf[\"pages\"] = Join(pages_arr, \", \")\n        inf[\"pages_count\"] = Len(pages_arr)\n        inf[\"snippets\"] = Join(blocks_arr, \", \")\n        inf[\"blocks_count\"] = Len(blocks_arr)\n        inf[\"menu\"] = Join(menu_arr, \", \")\n        inf[\"menu_count\"] = Len(menu_arr)\n        inf[\"parameters\"] = Join(parameters_arr, \", \")\n        inf[\"parameters_count\"] = Len(parameters_arr)\n        inf[\"languages\"] = Join(languages_arr, \", \")\n        inf[\"languages_count\"] = Len(languages_arr)\n        inf[\"contracts\"] = Join(contracts_arr, \", \")\n        inf[\"contracts_count\"] = Len(contracts_arr)\n        inf[\"tables\"] = Join(tables_arr, \", \")\n        inf[\"tables_count\"] = Len(tables_arr)\n        if 0 == inf[\"pages_count\"] + inf[\"blocks_count\"] + inf[\"menu_count\"] + inf[\"parameters_count\"] + inf[\"languages_count\"] + inf[\"contracts_count\"] + inf[\"tables_count\"] {\n            warning \"Invalid or empty import file\"\n        }\n        // IMPORT DATA\n        // the contracts is imported in one piece, the rest is cut under the $limit\n        var sliced contracts array\n        i = 0\n        while i < lenArrData {\n            var items array l int item map\n            while l < $limit && (i + l < lenArrData) {\n                item = arrData[i + l]\n                if item[\"Type\"] == \"contracts\" {\n                    contracts = Append(contracts, item)\n                } else {\n                    items = Append(items, item)\n                }\n                l = l + 1\n            }\n            var batch map\n            batch[\"Data\"] = JSONEncode(items)\n            sliced = Append(sliced, batch)\n            i = i + $limit\n        }\n        if Len(contracts) > 0 {\n            var batch map\n            batch[\"Data\"] = JSONEncode(contracts)\n            sliced = Append(sliced, batch)\n        }\n        input[\"data\"] = sliced\n        // storing\n        DBUpdate(\"@1buffer_data\", $import_id, {\"value\": input})\n        DBUpdate(\"@1buffer_data\", $info_id, {\"value\": inf})\n        var name string\n        name = Str(input[\"name\"])\n        var cndns string\n        cndns = Str(input[\"conditions\"])\n        if !DBFind(\"@1applications\").Columns(\"id\").Where({\"name\": name, \"ecosystem\": $ecosystem_id}).One(\"id\") {\n            DBInsert(\"@1applications\", {\"name\": name, \"conditions\": cndns, \"ecosystem\": $ecosystem_id})\n        }\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewAppParam.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewAppParam {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"app_params\").Columns(\"id\").Where({\"name\":$Name}).One(\"id\") {\n            warning Sprintf( \"Application parameter %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"app_params\", {app_id: $ApplicationId, name: $Name, value: $Value,\n              conditions: $Conditions})\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewApplication.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewApplication {\n    data {\n        Name string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if Size($Name) == 0 {\n            warning \"Application name missing\"\n        }\n\n        if DBFind(\"applications\").Columns(\"id\").Where({name:$Name}).One(\"id\") {\n            warning Sprintf( \"Application %s already exists\", $Name)\n        }\n    }\n\n    action {\n        $result = DBInsert(\"applications\", {name: $Name,conditions: $Conditions})\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewBadBlock.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewBadBlock {\n\tdata {\n\t\tProducerNodeID int\n\t\tConsumerNodeID int\n\t\tBlockID int\n\t\tTimestamp int\n\t\tReason string\n\t}\n\taction {\n        DBInsert(\"@1bad_blocks\", {producer_node_id: $ProducerNodeID,consumer_node_id: $ConsumerNodeID,\n            block_id: $BlockID, \"timestamp block_time\": $Timestamp, reason: $Reason})\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewContract.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewContract {\n    data {\n        ApplicationId int\n        Value string\n        Conditions string\n        TokenEcosystem int \"optional\"\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        $contract_name = ContractName($Value)\n\n        if !$contract_name {\n            error \"must be the name\"\n        }\n\n        if !$TokenEcosystem {\n            $TokenEcosystem = 1\n        } else {\n            if !SysFuel($TokenEcosystem) {\n                warning Sprintf(\"Ecosystem %d is not system\", $TokenEcosystem)\n            }\n        }\n    }\n\n    action {\n        $result = CreateContract($contract_name, $Value, $Conditions, $TokenEcosystem, $ApplicationId)\n    }\n    func price() int {\n        return SysParamInt(\"contract_price\")\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewEcosystem.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewEcosystem {\n\tdata {\n\t\tName  string\n\t}\n\taction {\n\t\t$result = CreateEcosystem($key_id, $Name)\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewLang.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewLang {\n    data {\n        ApplicationId int\n        Name string\n        Trans string\n    }\n\n    conditions {\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"languages\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Language resource %s already exists\", $Name)\n        }\n\n        EvalCondition(\"parameters\", \"changing_language\", \"value\")\n    }\n\n    action {\n        CreateLanguage($Name, $Trans)\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewMenu.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewMenu {\n    data {\n        Name string\n        Value string\n        Title string \"optional\"\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if DBFind(\"menu\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Menu %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"menu\", {name:$Name,value: $Value, title: $Title, conditions: $Conditions})\n    }\n    func price() int {\n        return SysParamInt(\"menu_price\")\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewPage.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewPage {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Menu string\n        Conditions string\n        ValidateCount int \"optional\"\n        ValidateMode string \"optional\"\n    }\n    func preparePageValidateCount(count int) int {\n        var min, max int\n        min = Int(EcosysParam(\"min_page_validate_count\"))\n        max = Int(EcosysParam(\"max_page_validate_count\"))\n\n        if count < min {\n            count = min\n        } else {\n            if count > max {\n                count = max\n            }\n        }\n        return count\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"pages\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Page %s already exists\", $Name)\n        }\n\n        $ValidateCount = preparePageValidateCount($ValidateCount)\n\n        if $ValidateMode {\n            if $ValidateMode != \"1\" {\n                $ValidateMode = \"0\"\n            }\n        }\n    }\n\n    action {\n        DBInsert(\"pages\", {name: $Name,value: $Value, menu: $Menu,\n             validate_count:$ValidateCount,validate_mode: $ValidateMode,\n             conditions: $Conditions,app_id: $ApplicationId})\n    }\n    func price() int {\n        return SysParamInt(\"page_price\")\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewParameter.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewParameter {\n    data {\n        Name string\n        Value string\n        Conditions string\n    }\n    func warnEmpty(name value string) {\n        if Size(value) == 0 {\n            warning Sprintf(LangRes(\"@1x_parameter_empty\"),name)\n        }\n    }\n    conditions {\n        DeveloperCondition()\n\n        ValidateCondition($Conditions, $ecosystem_id)\n        $Name = TrimSpace($Name)\n        warnEmpty(\"Name\",$Name)\n        if DBFind(\"@1parameters\").Where({\"name\": $Name, \"ecosystem\": $ecosystem_id}).One(\"id\") {\n            warning Sprintf(LangRes(\"@1template_parameter_exists\"), $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"@1parameters\", {\"name\": $Name, \"value\": $Value, \"conditions\": $Conditions, \"ecosystem\": $ecosystem_id})\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewSnippet.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewSnippet {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"snippets\").Columns(\"id\").Where({name:$Name}).One(\"id\") {\n            warning Sprintf( \"Block %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"snippets\", {name: $Name, value: $Value, conditions: $Conditions,\n              app_id: $ApplicationId})\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewTable.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NewTable {\n    data {\n        ApplicationId int\n        Name string\n        Columns string\n        Permissions string\n    }\n    conditions {\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n        TableConditions($Name, $Columns, $Permissions)\n    }\n    \n    action {\n        CreateTable($Name, $Columns, $Permissions, $ApplicationId)\n    }\n    func price() int {\n        return SysParamInt(\"table_price\")\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NewUser.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"NodeOwnerCondition\")'\ncontract NewUser {\n    data {\n        NewPubkey string \"optional\"\n        Ecosystem int \"optional\"\n    }\n    func getEcosystem() {\n        $e_id = Int($Ecosystem)\n        if $e_id == 0 {\n            $e_id = $ecosystem_id\n        }\n        $eco = DBFind(\"@1ecosystems\").Where({\"id\": $e_id}).Row()\n        if !$eco {\n            warning Sprintf(LangRes(\"@1ecosystem_not_found\"), $e_id)\n        }\n    }\n    func canOpt() bool {\n        return $free_membership == 1 || $e_id == 1\n    }\n    conditions {\n        getEcosystem()\n        $newId = PubToID($NewPubkey)\n\n        if $newId == 0 {\n            warning LangRes(\"@1wrong_pub\")\n        }\n        if Size($NewPubkey) == 0 {\n            warning \"You did not enter the public key\"\n        }\n        $pub = HexToPub($NewPubkey)\n        $account = IdToAddress($newId)\n\n        $k = DBFind(\"@1keys\").Where({\"id\": $newId, \"account\": $account, \"ecosystem\": $e_id}).Row()\n\n        $free_membership = Int(DBFind(\"@1parameters\").Where({\"ecosystem\": $e_id, \"name\": \"free_membership\"}).One(\"value\"))\n    }\n\n    action {\n        var iscan bool\n        iscan = canOpt()\n        if !iscan {\n            warning Sprintf(LangRes(\"@1eco_no_open_new_user\"), $eco[\"name\"], $e_id)\n        }\n        if $k {\n            var kid int kpub string\n            kid = Int($k[\"id\"])\n            kpub = $k[\"pub\"]\n            if Size(kpub) != 0 {\n                warning Sprintf(LangRes(\"@1template_user_exists\"), IdToAddress($newId))\n            }\n            DBUpdateExt(\"@1keys\", {\"id\": kid, \"ecosystem\": $e_id}, {\"pub\": $pub})\n            $result = $account\n        }else{\n            DBInsert(\"@1keys\", {\"id\": $newId, \"account\": $account, \"pub\": $pub, \"ecosystem\": $e_id})\n            if !DBFind(\"@1keys\").Where({\"ecosystem\": 1, \"account\": $account}).Row() {\n                DBInsert(\"@1keys\", {\"id\": $newId, \"account\": $account, \"pub\": $pub, \"ecosystem\": 1})\n                var h map\n                $whiteHoleBalance = DBFind(\"@1keys\").Where({\"account\": $white_hole_account,\"ecosystem\":1}).Columns(\"amount\").One(\"amount\")\n                h[\"sender_id\"] =$white_hole_key\n                h[\"sender_balance\"] = $whiteHoleBalance\n                h[\"recipient_id\"] = $newId\n                h[\"comment\"] = \"New User\"\n                h[\"block_id\"] = $block\n                h[\"txhash\"] = $txhash\n                h[\"ecosystem\"] = 1\n                h[\"type\"] = 4\n                h[\"created_at\"] = $time\n                DBInsert(\"@1history\", h)\n            }\n            $result = $account\n        }\n        var h map\n        $whiteHoleBalance = DBFind(\"@1keys\").Where({\"account\": $white_hole_account,\"ecosystem\":$ecosystem_id}).Columns(\"amount\").One(\"amount\")\n        h[\"sender_id\"] =$white_hole_key\n        h[\"sender_balance\"] = $whiteHoleBalance\n        h[\"recipient_id\"] = $newId\n        h[\"comment\"] = \"New User\"\n        h[\"block_id\"] = $block\n        h[\"txhash\"] = $txhash\n        h[\"ecosystem\"] = $ecosystem_id\n        h[\"type\"] = 4\n        h[\"created_at\"] = $time\n        DBInsert(\"@1history\", h)\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/NodeOwnerCondition.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract NodeOwnerCondition {\n\tconditions {\n        $raw_honor_nodes = SysParamString(\"honor_nodes\")\n        if Size($raw_honor_nodes) == 0 {\n            ContractConditions(\"MainCondition\")\n        } else {\n            $honor_nodes = JSONDecode($raw_honor_nodes)\n            var i int\n            while i < Len($honor_nodes) {\n                $fn = $honor_nodes[i]\n                if $fn[\"key_id\"] == $key_id {\n                    return true\n                }\n                i = i + 1\n            }\n            warning \"NodeOwnerCondition: Sorry, you do not have access to this action.\"\n        }\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/UnbindWallet.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract UnbindWallet {\n\tdata {\n\t\tId         int\n\t}\n\tconditions {\n\t\t$cur = DBRow(\"contracts\").Columns(\"id,conditions,wallet_id\").WhereId($Id)\n\t\tif !$cur {\n\t\t\terror Sprintf(\"Contract %d does not exist\", $Id)\n\t\t}\n\t\t\n\t\tEval($cur[\"conditions\"])\n\t\tif $key_id != Int($cur[\"wallet_id\"]) {\n\t\t\terror Sprintf(\"Wallet %d cannot deactivate the contract\", $key_id)\n\t\t}\n\t}\n\taction {\n\t\tUnbndWallet($Id, $ecosystem_id)\n\t}\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/UpdatePlatformParam.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract UpdatePlatformParam {\n     data {\n        Name string\n        Value string\n        Conditions string \"optional\"\n     }\n     conditions {\n         if !GetContractByName($Name){\n            warning \"System parameter not found\"\n         }\n     }\n     action {\n        var params map\n        params[\"Value\"] = $Value\n        CallContract($Name, params)\n        \n        DBUpdatePlatformParam($Name, $Value, $Conditions)\n     }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/UploadBinary.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract UploadBinary {\n    data {\n        ApplicationId int\n        Name string\n        Data bytes\n        DataMimeType string \"optional\"\n        MemberAccount string \"optional\"\n    }\n    conditions {\n        if Size($MemberAccount) > 0 {\n            $UserID = $MemberAccount\n        } else {\n            $UserID = $account_id\n        }\n        $Id = Int(DBFind(\"@1binaries\").Columns(\"id\").Where({\"app_id\": $ApplicationId, \n                \"account\": $UserID, \"name\": $Name, \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $Id == 0 {\n            if $ApplicationId == 0 {\n                warning LangRes(\"@1aid_cannot_zero\")\n            }\n        }\n    }\n    action {\n        var hash string\n        hash = Hash($Data)\n        if $DataMimeType == \"\" {\n            $DataMimeType = \"application/octet-stream\"\n        }\n        if $Id != 0 {\n            DBUpdate(\"@1binaries\", $Id, {\"data\": $Data, \"hash\": hash, \"mime_type\": $DataMimeType})\n        } else {\n            $Id = DBInsert(\"@1binaries\", {\"app_id\": $ApplicationId, \"account\": $UserID,\n                \"name\": $Name, \"data\": $Data, \"hash\": hash, \"mime_type\": $DataMimeType, \"ecosystem\": $ecosystem_id})\n        }\n        $result = $Id\n    }\n}"
  },
  {
    "path": "packages/migration/contracts/first_ecosystem/UploadFile.sim",
    "content": "// +prop AppID = '1'\n// +prop Conditions = 'ContractConditions(\"MainCondition\")'\ncontract UploadFile {\n    data {\n        ApplicationId int\n        Data file\n        Name string \"optional\"\n    }\n    conditions {\n        if $Name == \"\" {\n            $Name = $Data[\"Name\"]\n        }\n        $Body = $Data[\"Body\"]\n        $DataMimeType = $Data[\"MimeType\"]\n    }\n    action {\n        $Id = @1UploadBinary(\"ApplicationId,Name,Data,DataMimeType\", $ApplicationId, $Name, $Body, $DataMimeType)\n        $result = $Id\n    }\n}"
  },
  {
    "path": "packages/migration/contracts_data.go",
    "content": "// Code generated by go generate; DO NOT EDIT.\n\npackage migration\n\nvar contractsDataSQL = `\nINSERT INTO \"1_contracts\" (id, name, value, token_id, conditions, app_id, ecosystem)\nVALUES\n\t(next_id('1_contracts'), 'DeveloperCondition', '// This contract is used to set \"developer\" rights.\n// Usually the \"developer\" role is used for this.\n// The role ID is written to the ecosystem parameter and can be changed.\n// The contract requests the role ID from the ecosystem parameter and the contract checks the rights.\n\ncontract DeveloperCondition {\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n    }\n    conditions {\n        chooseControl()\n        if $control[\"control_mode\"] == 2{\n            return\n        }\n        // check for Founder\n        if EcosysParam(\"founder_account\") == AddressToId($account_id) {\n            return\n        }\n        // check for Developer role\n        var app_id int role_id string\n        app_id = Int(DBFind(\"@1applications\").Where({\"ecosystem\": $ecosystem_id, \"name\": \"System\"}).One(\"id\"))\n        role_id = AppParam(app_id, \"role_developer\", $ecosystem_id)\n\n        if Size(role_id) == 0 {\n            warning Sprintf(LangRes(\"@1x_not_access_action\"),\"DeveloperCondition\")\n        }\n        if !RoleAccess(Int(role_id)) {\n            warning Sprintf(LangRes(\"@1x_not_access_action\"),\"DeveloperCondition\")\n        }\n    }\n}\n', '{{.Ecosystem}}', 'ContractConditions(\"MainCondition\")', '{{.AppID}}', '{{.Ecosystem}}'),\n\t(next_id('1_contracts'), 'MainCondition', 'contract MainCondition {\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n    }\n\tconditions {\n\t    chooseControl()\n        if $control[\"control_mode\"] == 2{\n            return\n        }\n\t\tif EcosysParam(\"founder_account\")!=$key_id\n\t\t{\n\t\t\twarning \"MainCondition: Sorry, you do not have access to this action.\"\n\t\t}\n\t}\n}\n', '{{.Ecosystem}}', 'ContractConditions(\"MainCondition\")', '{{.AppID}}', '{{.Ecosystem}}');\n`"
  },
  {
    "path": "packages/migration/data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\n//go:generate go run ./gen/contracts.go\n\nvar (\n\tmigrationInitialTables = `\n\t{{headseq \"migration_history\"}}\n\t\tt.Column(\"id\", \"int\", {\"default_raw\": \"nextval('migration_history_id_seq')\"})\n\t\tt.Column(\"version\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"date_applied\", \"int\", {})\n\t{{footer \"seq\" \"primary\"}}\n\n\t{{head \"block_chain\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"rollbacks_hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"data\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"ecosystem_id\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"key_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"node_position\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"time\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"tx\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"consensus_mode\", \"int\", {\"default\": \"1\"})\n\t\tt.Column(\"candidate_nodes\", \"bytea\", {\"default\": \"\\x\"})\n\t{{footer \"primary\" \"index(node_position, time)\"}}\n\n\t{{head \"confirmations\"}}\n\t\tt.Column(\"block_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"good\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"bad\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"time\", \"bigint\", {\"default\": \"0\"})\n\t{{footer \"primary(block_id)\"}}\n\n\t{{head \"info_block\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"rollbacks_hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"block_id\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"node_position\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"key_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"time\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"current_version\", \"string\", {\"default\": \"0.0.1\", \"size\": 50})\n\t\tt.Column(\"sent\", \"smallint\", {\"default\": \"0\"})\n\t\tt.Column(\"consensus_mode\", \"int\", {\"default\": \"1\"})\n\t\tt.Column(\"candidate_nodes\", \"bytea\", {\"default\": \"\\x\"})\n\t{{footer \"index(sent)\"}}\n\n\t{{head \"install\"}}\n\t\tt.Column(\"progress\", \"string\", {\"default\": \"\", \"size\":10})\n\t{{footer}}\n\n\t{{head \"log_transactions\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"block\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"timestamp\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"contract_name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"address\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"status\", \"bigint\", {\"default\": \"0\"})\n\t{{footer \"primary(hash)\"}}\n\n\t{{head \"queue_blocks\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"honor_node_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"block_id\", \"int\", {\"default\": \"0\"})\n\t{{footer \"primary(hash)\"}}\n\n\t{{head \"queue_tx\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"data\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"from_gate\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"expedite\", \"decimal(30)\", {\"default_raw\": \"'0' CHECK (expedite >= 0)\"})\n\t\tt.Column(\"time\", \"bigint\", {\"default\": \"0\"})\n\t{{footer \"primary(hash)\"}}\n\n\t{{headseq \"rollback_tx\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default_raw\": \"nextval('rollback_tx_id_seq')\"})\n\t\tt.Column(\"block_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"tx_hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"table_name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"table_id\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"data_hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"data\", \"text\", {\"default\": \"\"})\n\t{{footer \"seq\" \"primary\" \"index(table_name, table_id, block_id)\"}}\n\n\t{{head \"stop_daemons\"}}\n\t\tt.Column(\"stop_time\", \"int\", {\"default\": \"0\"})\n\t{{footer}}\n\n\t{{head \"spent_info\"}}\n\t\tt.Column(\"input_tx_hash\", \"bytea\", {\"null\": true})\n\t\tt.Column(\"input_index\", \"integer\", {\"null\": true})\n\t\tt.Column(\"output_tx_hash\", \"bytea\")\n\t\tt.Column(\"output_index\", \"integer\")\n\t\tt.Column(\"output_key_id\", \"bigint\")\n\t\tt.Column(\"output_value\", \"decimal(30)\", {\"default_raw\": \"'0' CHECK (output_value >= 0)\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"block_id\", \"bigint\")\n\t\tt.Column(\"type\", \"bigint\")\n\t{{footer \"primary(output_tx_hash,output_key_id,output_index)\" \"index(block_id)\" \"index(input_tx_hash)\" \"index(output_key_id)\" \"index(output_tx_hash)\"}}\n\n\t{{head \"transactions\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"data\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"used\", \"smallint\", {\"default\": \"0\"})\n\t\tt.Column(\"high_rate\", \"smallint\", {\"default\": \"0\"})\n\t\tt.Column(\"expedite\", \"decimal(30)\", {\"default_raw\": \"'0' CHECK (expedite >= 0)\"})\n\t\tt.Column(\"time\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"type\", \"smallint\", {\"default\": \"0\"})\n\t\tt.Column(\"key_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"sent\", \"smallint\", {\"default\": \"0\"})\n\t\tt.Column(\"verified\", \"smallint\", {\"default\": \"1\"})\n\t{{footer \"primary(hash)\" \"index(sent, used, verified, high_rate)\"}}\n\n\t{{head \"transactions_status\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"time\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"type\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"int\", {\"default\": \"1\"})\n\t\tt.Column(\"wallet_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"block_id\", \"int\", {\"default\": \"0\"})\n\t\tt.Column(\"error\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"penalty\", \"int\", {\"default\": \"0\"})\n\t{{footer \"primary(hash)\"}}\n\n`\n\n\tmigrationInitialSchema = `\n\t\tCREATE OR REPLACE FUNCTION next_id(table_name TEXT, OUT result INT) AS\n\t\t$$\n\t\tBEGIN\n\t\t\tEXECUTE FORMAT('SELECT COUNT(*) + 1 FROM \"%s\"', table_name)\n\t\t\tINTO result;\n\t\t\tRETURN;\n\t\tEND\n\t\t$$\n\t\tLANGUAGE plpgsql;`\n\n\ttentative = `\n\t{{head \"external_blockchain\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"url\", \"string\", {\"default\":\"\", \"size\":255})\n\t\tt.Column(\"external_contract\", \"string\", {\"default\":\"\", \"size\":255})\n\t\tt.Column(\"result_contract\", \"string\", {\"default\":\"\", \"size\":255})\n\t\tt.Column(\"uid\", \"string\", {\"default\":\"\", \"size\":255})\n\t\tt.Column(\"tx_time\", \"int\", {\"default\":\"0\"})\n\t\tt.Column(\"sent\", \"int\", {\"default\":\"0\"})\n\t\tt.Column(\"hash\", \"bytea\", {\"default\":\"\"})\n\t\tt.Column(\"attempts\", \"int\", {\"default\":\"0\"})\n\t{{footer \"primary\"}}\n\n\t{{head \"transactions_attempts\"}}\n\t\tt.Column(\"hash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"attempt\", \"smallint\", {\"default\": \"0\"})\n\t{{footer \"primary(hash)\" \"index(attempt)\"}}\n\n\t`\n)\n"
  },
  {
    "path": "packages/migration/ecosystem.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/gobuffalo/fizz\"\n\t\"github.com/gobuffalo/fizz/translators\"\n)\n\ntype SqlData struct {\n\tEcosystem   int\n\tWallet      int64\n\tName        string\n\tFounder     int64\n\tAppID       int64\n\tAccount     string\n\tDigits      int64\n\tTokenSymbol string\n\tTokenName   string\n}\n\nvar _ fizz.Translator = (*translators.Postgres)(nil)\nvar pgt = translators.NewPostgres()\nvar tblName string\n\nconst (\n\tsqlPrimary = \"primary\"\n\tsqlUnique  = \"unique\"\n\tsqlIndex   = \"index\"\n\tsqlSeq     = \"seq\"\n)\n\nfunc sqlHeadSequence(name string) string {\n\tret := fmt.Sprintf(`sql(\"DROP SEQUENCE IF EXISTS %[1]s_id_seq CASCADE;\")\nsql(\"CREATE SEQUENCE %[1]s_id_seq START WITH 1;\")`, name)\n\n\treturn ret + \"\\r\\n\" + sqlHead(name)\n}\n\nfunc sqlHead(name string) string {\n\ttblName = name\n\treturn fmt.Sprintf(`sql(\"DROP TABLE IF EXISTS \\\"%[1]s\\\";\")\n\tcreate_table(\"%[1]s\") {`, name)\n}\n\nfunc sqlEnd(options ...string) (ret string) {\n\tret = `t.DisableTimestamps()\n\t}`\n\tfor _, opt := range options {\n\t\tvar cname string\n\t\tif strings.HasPrefix(opt, sqlSeq) {\n\t\t\tret += fmt.Sprintf(`\n\t\tsql(\"ALTER SEQUENCE %[1]s_id_seq owned by %[1]s.id;\")`, tblName)\n\t\t\tcontinue\n\t\t}\n\t\tif strings.HasPrefix(opt, sqlPrimary) {\n\t\t\tif opt == sqlPrimary {\n\t\t\t\topt = `PRIMARY KEY (id)`\n\t\t\t} else {\n\t\t\t\topt = strings.Replace(opt, sqlPrimary, `PRIMARY KEY `, 1)\n\t\t\t}\n\t\t\tcname = \"pkey\"\n\t\t}\n\t\tif strings.HasPrefix(opt, sqlUnique) {\n\t\t\tpars := strings.Split(strings.Trim(opt[len(sqlUnique):], `() `), `,`)\n\t\t\topt = strings.Replace(opt, sqlUnique, `UNIQUE `, 1)\n\t\t\tfor i, val := range pars {\n\t\t\t\tpars[i] = strings.TrimSpace(val)\n\t\t\t}\n\t\t\tcname = strings.Join(pars, `_`)\n\t\t}\n\t\tif strings.HasPrefix(opt, sqlIndex) {\n\t\t\tpars := strings.Split(strings.Trim(opt[len(sqlIndex):], `() `), `,`)\n\t\t\tfor i, val := range pars {\n\t\t\t\tpars[i] = strings.TrimSpace(val)\n\t\t\t}\n\t\t\tif len(pars) == 1 {\n\t\t\t\tret += fmt.Sprintf(`\n\t\tadd_index(\"%s\", \"%s\", {})`, tblName, pars[0])\n\t\t\t} else {\n\t\t\t\tret += fmt.Sprintf(`\n\t\tadd_index(\"%s\", [\"%s\"], {})`, tblName, strings.Join(pars, `\", \"`))\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tret += fmt.Sprintf(`\n\tsql(\"ALTER TABLE ONLY \\\"%[1]s\\\" ADD CONSTRAINT \\\"%[1]s_%[3]s\\\" %[2]s;\")`, tblName, opt, cname)\n\t}\n\treturn\n}\n\nfunc sqlConvert(in []string) (ret string, err error) {\n\tvar item string\n\tfuncs := template.FuncMap{\n\t\t\"head\":    sqlHead,\n\t\t\"footer\":  sqlEnd,\n\t\t\"headseq\": sqlHeadSequence,\n\t}\n\tsqlTmpl := template.New(\"sql\").Funcs(funcs)\n\tfor _, sql := range in {\n\t\tvar (\n\t\t\ttmpl *template.Template\n\t\t\tout  bytes.Buffer\n\t\t)\n\n\t\tif tmpl, err = sqlTmpl.Parse(sql); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif err = tmpl.Execute(io.Writer(&out), nil); err != nil {\n\t\t\treturn\n\t\t}\n\t\titem, err = fizz.AString(out.String(), pgt)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tret += item + \"\\r\\n\"\n\t}\n\treturn\n}\n\nfunc sqlTemplate(input []string, data any) (ret string, err error) {\n\tfor _, item := range input {\n\t\tvar (\n\t\t\tout  bytes.Buffer\n\t\t\ttmpl *template.Template\n\t\t)\n\t\ttmpl, err = template.New(\"sql\").Parse(item)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif err = tmpl.Execute(io.Writer(&out), data); err != nil {\n\t\t\treturn\n\t\t}\n\t\tret += out.String() + \"\\r\\n\"\n\t}\n\treturn\n}\n\n// GetEcosystemScript returns script to create ecosystem\nfunc GetEcosystemScript(data SqlData) (string, error) {\n\treturn sqlTemplate([]string{\n\t\tcontractsDataSQL,\n\t\tmenuDataSQL,\n\t\tpagesDataSQL,\n\t\tparametersDataSQL,\n\t\tmembersDataSQL,\n\t\tsectionsDataSQL,\n\t\tkeysDataSQL,\n\t}, data)\n}\n\n// GetFirstEcosystemScript returns script to update with additional data for first ecosystem\nfunc GetFirstEcosystemScript(data SqlData) (ret string, err error) {\n\tret, err = sqlConvert([]string{\n\t\tsqlFirstEcosystemSchema,\n\t})\n\tif err != nil {\n\t\treturn\n\t}\n\tvar out string\n\tout, err = sqlTemplate([]string{\n\t\tfirstDelayedContractsDataSQL,\n\t\tfirstEcosystemDataSQL,\n\t}, data)\n\tret += out\n\n\tscripts := []string{\n\t\tfirstEcosystemContractsSQL,\n\t\tfirstEcosystemPagesDataSQL,\n\t\tfirstEcosystemBlocksDataSQL,\n\t\tplatformParametersDataSQL,\n\t\tfirstTablesDataSQL,\n\t}\n\tret += strings.Join(scripts, \"\\r\\n\")\n\treturn\n}\n\n// GetFirstTableScript returns script to update _tables for first ecosystem\nfunc GetFirstTableScript(data SqlData) (string, error) {\n\treturn sqlTemplate([]string{\n\t\ttablesDataSQL,\n\t}, data)\n}\n\n// GetCommonEcosystemScript returns script with common tables\nfunc GetCommonEcosystemScript() (string, error) {\n\tsql, err := sqlConvert([]string{\n\t\tsqlFirstEcosystemCommon,\n\t\tsqlTimeZonesSQL,\n\t})\n\tif err != nil {\n\t\treturn ``, err\n\t}\n\treturn sql + \"\\r\\n\" + timeZonesSQL, nil\n}\n"
  },
  {
    "path": "packages/migration/ecosystem_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestGetEcosystemScript(t *testing.T) {\n\tstr := fmt.Sprintf(GetFirstEcosystemScript(SqlData{Wallet: -1744264011260937456}))\n\tpath, _ := os.Getwd()\n\tos.WriteFile(path+\"/eco.sql\", []byte(str), 0777)\n}\n"
  },
  {
    "path": "packages/migration/first_delayed_contracts.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar firstDelayedContractsDataSQL = `INSERT INTO \"1_delayed_contracts\"\n\t\t(\"id\", \"contract\", \"key_id\", \"block_id\", \"every_block\", \"high_rate\", \"conditions\")\n\tVALUES\n\t\t(next_id('1_delayed_contracts'), '@1CheckNodesBan', '{{.Wallet}}', '10', '10', '4','ContractConditions(\"@1MainCondition\")');\n`\n"
  },
  {
    "path": "packages/migration/first_ecosys_contracts_data.go",
    "content": "// Code generated by go generate; DO NOT EDIT.\n\npackage migration\n\nvar firstEcosystemContractsSQL = `\nINSERT INTO \"1_contracts\" (id, name, value, token_id, conditions, app_id, ecosystem)\nVALUES\n\t(next_id('1_contracts'), 'AccessControlMode', 'contract AccessControlMode {\n    data {\n        VotingId int \"optional\"\n    }\n\n    func decentralizedAutonomous(){\n        if !DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":2}).Row(){\n            warning \"control mode DAO error\"\n        }\n        var prev string\n        prev = $stack[0]\n        if Len($stack) > 3{\n            prev = $stack[Len($stack) - 3]\n        }\n        if prev != \"@1VotingDecisionCheck\" {\n            warning LangRes(\"@1contract_start_votingdecisioncheck_only\")\n        }\n\n        $voting = DBFind(\"@1votings\").Where({\"ecosystem\": $ecosystem_id, \"id\": $VotingId,\"voting->name\":{\"$begin\":\"voting_for_control_mode_template\"}}).Columns(\"voting->type_decision,flags->success,voting->type\").Row()\n        if Int($voting[\"voting.type\"]) != 2 {\n            warning LangRes(\"@1voting_type_invalid\")\n        }\n        if Int($voting[\"voting.type_decision\"]) != 4 {\n            warning LangRes(\"@1voting_error_decision\")\n        }\n        if Int($voting[\"flags.success\"]) != 1 {\n            warning LangRes(\"@1voting_error_success\")\n        }\n    }\n    func chooseControl(){\n        $control = DBFind(\"@1ecosystems\").Where({\"id\":$ecosystem_id,\"control_mode\":{\"$in\":[\"1\",\"2\"]}}).Row()\n        if !$control{\n            warning \"control mode error\"\n        }\n\n        if $control[\"control_mode\"] == 2 && $VotingId{\n            decentralizedAutonomous()\n            return\n        }\n        DeveloperCondition()\n    }\n    conditions {\n        $VotingId = Int($VotingId)\n        chooseControl()\n        $result = $control[\"control_mode\"]\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'AccessVoteTempRun', 'contract AccessVoteTempRun {\n    data {\n        ContractAccept string \"optional\"\n        ContractAcceptParams map \"optional\"\n    }\n\n    func votingCheck(){\n        var app_id int\n        app_id = Int(DBFind(\"@1applications\").Where({\"ecosystem\": $ecosystem_id, \"name\": \"Basic\"}).One(\"id\"))\n        $templateId = Int(DBFind(\"@1app_params\").Where({\"app_id\": app_id, \"name\": \"voting_template_control_mode\", \"ecosystem\": $ecosystem_id}).One(\"value\"))\n        if $templateId == 0 {\n            warning LangRes(\"@1template_id_not_found\")\n        }\n    }\n\n    action {\n        votingCheck()\n        var temp map\n        temp[\"TemplateId\"] = $templateId\n        temp[\"Duration\"] = 7\n        temp[\"ContractAccept\"] = $ContractAccept\n        temp[\"ContractAcceptParams\"] = JSONEncode($ContractAcceptParams)\n        CallContract(\"@1VotingTemplateRun\",temp)\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'BindWallet', 'contract BindWallet {\n\tdata {\n\t\tId  int\n\t}\n\tconditions {\n\t\t$cur = DBRow(\"contracts\").Columns(\"id,conditions,wallet_id\").WhereId($Id)\n\t\tif !$cur {\n\t\t\terror Sprintf(\"Contract %d does not exist\", $Id)\n\t\t}\n\t\tEval($cur[\"conditions\"])\n\t\tif $key_id != Int($cur[\"wallet_id\"]) {\n\t\t\terror Sprintf(\"Wallet %d cannot activate the contract\", $key_id)\n\t\t}\n\t}\n\taction {\n\t\tBndWallet($Id, $ecosystem_id)\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'CallDelayedContract', 'contract CallDelayedContract {\n\tdata {\n        Id int\n\t}\n\n\tconditions {\n\t\tHonorNodeCondition()\n\n\t\tvar rows array\n\t\trows = DBFind(\"@1delayed_contracts\").Where({\"id\": $Id, \"deleted\": 0})\n\n\t\tif !Len(rows) {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_not_exist\"), $Id)\n\t\t}\n\t\t$cur = rows[0]\n\t\t$limit = Int($cur[\"limit\"])\n\t\t$counter = Int($cur[\"counter\"])\n\n\t\tif $block < Int($cur[\"block_id\"]) {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_error\"), $Id, $cur[\"block_id\"], $block)\n\t\t}\n\n\t\tif $limit > 0 && $counter >= $limit {\n\t\t\twarning Sprintf(LangRes(\"@1template_delayed_contract_limited\"), $Id)\n\t\t}\n\t}\n\n\taction {\n\t\t$counter = $counter + 1\n\n\t\tvar block_id int\n\t\tblock_id = $block\n\t\tif $limit == 0 || $limit > $counter {\n\t\t\tblock_id = block_id + Int($cur[\"every_block\"])\n\t\t}\n\n\t\tDBUpdate(\"@1delayed_contracts\", $Id, {\"counter\": $counter, \"block_id\": block_id})\n\n\t\tvar params map\n\t\tCallContract($cur[\"contract\"], params)\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'CheckNodesBan', 'contract CheckNodesBan {\n    func getPermission() {\n        var array_permissions array result i int prevContract string\n        array_permissions = [\"@1CheckNodesBan\"]\n\n        prevContract = $stack[0]\n        if Len($stack) > 2 {\n            prevContract = $stack[Len($stack) - 2]\n        }\n        while i < Len(array_permissions) {\n            var contract_name string\n            contract_name = array_permissions[i]\n            if contract_name == prevContract {\n                result = 1\n            }\n            i = i + 1\n        }\n\n        if result == 0 {\n            warning LangRes(\"@1contract_chain_distorted\")\n        }\n    }\n    conditions {\n        getPermission()\n        HonorNodeCondition()\n        var rows array\n        rows = DBFind(\"@1delayed_contracts\").Where({\"contract\": \"@1CheckNodesBan\", \"deleted\": 0})\n        if !Len(rows) {\n            warning Sprintf(LangRes(\"@1template_delayed_contract_not_exist\"), $Id)\n        }\n        $cur = rows[0]\n        $counter = Int($cur[\"counter\"]) + 1\n        $Id = Int($cur[\"id\"])\n    }\n    action {\n        DBUpdateExt(\"@1delayed_contracts\", {\"id\":$Id}, {\"counter\": $counter})\n\n        UpdateNodesBan($block_time)\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditAppParam', 'contract EditAppParam {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"app_params\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"app_params\", $Id, pars)\n        }\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditApplication', 'contract EditApplication {\n    data {\n        ApplicationId int\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && false\n    }\n\n    conditions {\n        RowConditions(\"applications\", $ApplicationId, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"applications\", $ApplicationId, pars)\n        }\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditColumn', 'contract EditColumn {\n    data {\n        TableName string\n        Name string\n        Permissions string\n    }\n\n    conditions {\n        ColumnCondition($TableName, $Name, \"\", $Permissions)\n    }\n\n    action {\n        PermColumn($TableName, $Name, $Permissions)\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditContract', 'contract EditContract {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"contracts\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        $cur = DBFind(\"contracts\").Columns(\"id,value,conditions,wallet_id,token_id\").WhereId($Id).Row()\n        if !$cur {\n            error Sprintf(\"Contract %d does not exist\", $Id)\n        }\n        if $Value {\n            ValidateEditContractNewValue($Value, $cur[\"value\"])\n        }\n   \n        $recipient = Int($cur[\"wallet_id\"])\n    }\n\n    action {\n        UpdateContract($Id, $Value, $Conditions, $recipient, $cur[\"token_id\"])\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditLang', 'contract EditLang {\n    data {\n        Id int\n        Trans string\n    }\n\n    conditions {\n        EvalCondition(\"parameters\", \"changing_language\", \"value\")\n        $lang = DBFind(\"languages\").Where({id: $Id}).Row()\n    }\n\n    action {\n        EditLanguage($Id, $lang[\"name\"], $Trans)\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditMenu', 'contract EditMenu {\n    data {\n        Id int\n        Value string \"optional\"\n        Title string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value && !$Title\n    }\n\n    conditions {\n        RowConditions(\"menu\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Title {\n            pars[\"title\"] = $Title\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"menu\", $Id, pars)\n        }            \n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditPage', 'contract EditPage {\n    data {\n        Id int\n        Value string \"optional\"\n        Menu string \"optional\"\n        Conditions string \"optional\"\n        ValidateCount int \"optional\"\n        ValidateMode string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value && !$Menu && !$ValidateCount \n    }\n    func preparePageValidateCount(count int) int {\n        var min, max int\n        min = Int(EcosysParam(\"min_page_validate_count\"))\n        max = Int(EcosysParam(\"max_page_validate_count\"))\n        if count < min {\n            count = min\n        } else {\n            if count > max {\n                count = max\n            }\n        }\n        return count\n    }\n\n    conditions {\n        RowConditions(\"pages\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        $ValidateCount = preparePageValidateCount($ValidateCount)\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Menu {\n            pars[\"menu\"] = $Menu\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if $ValidateCount {\n            pars[\"validate_count\"] = $ValidateCount\n        }\n        if $ValidateMode {\n            if $ValidateMode != \"1\" {\n                $ValidateMode = \"0\"\n            }\n            pars[\"validate_mode\"] = $ValidateMode\n        }\n        if pars {\n            DBUpdate(\"pages\", $Id, pars)\n        }\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditParameter', 'contract EditParameter {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        DeveloperCondition()\n\n        RowConditions(\"@1parameters\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n        if $Value {\n            $Name = DBFind(\"@1parameters\").Where({\"id\": $Id, \"ecosystem\": $ecosystem_id}).One(\"name\")\n            if $Name == \"founder_account\" {\n                var account string\n                account = IdToAddress(Int($Value))\n                if !DBFind(\"@1keys\").Where({\"account\": account, \"ecosystem\": $ecosystem_id, \"deleted\": 0}).One(\"id\") {\n                    warning Sprintf(LangRes(\"@1template_user_not_found\"), $Value)\n                }\n            }\n            if $Name == \"max_block_user_tx\" || $Name == \"money_digit\" || $Name == \"max_sum\" || $Name == \"min_page_validate_count\" || $Name == \"max_page_validate_count\" {\n                if Size($Value) == 0 {\n                    warning LangRes(\"@1value_not_received\")\n                }\n                if Int($Value) <= 0 {\n                    warning LangRes(\"@1value_must_greater_zero\")\n                }\n            }\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            if $Value == ` + \"`\" + `\"\"` + \"`\" + ` {\n                pars[\"value\"] = \"\"\n            } else {\n                pars[\"value\"] = $Value\n            }\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"@1parameters\", $Id, pars)\n        }\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditSnippet', 'contract EditSnippet {\n    data {\n        Id int\n        Value string \"optional\"\n        Conditions string \"optional\"\n    }\n    func onlyConditions() bool {\n        return $Conditions && !$Value\n    }\n\n    conditions {\n        RowConditions(\"snippets\", $Id, onlyConditions())\n        if $Conditions {\n            ValidateCondition($Conditions, $ecosystem_id)\n        }\n    }\n\n    action {\n        var pars map\n        if $Value {\n            pars[\"value\"] = $Value\n        }\n        if $Conditions {\n            pars[\"conditions\"] = $Conditions\n        }\n        if pars {\n            DBUpdate(\"snippets\", $Id, pars)\n        }\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'EditTable', 'contract EditTable {\n    data {\n        Name string\n        InsertPerm string\n        UpdatePerm string\n        NewColumnPerm string\n        ReadPerm string \"optional\"\n    }\n\n    conditions {\n        if !$InsertPerm {\n            info(\"Insert condition is empty\")\n        }\n        if !$UpdatePerm {\n            info(\"Update condition is empty\")\n        }\n        if !$NewColumnPerm {\n            info(\"New column condition is empty\")\n        }\n\n        var permissions map\n        permissions[\"insert\"] = $InsertPerm\n        permissions[\"update\"] = $UpdatePerm\n        permissions[\"new_column\"] = $NewColumnPerm\n        if $ReadPerm {\n            permissions[\"read\"] = $ReadPerm\n        }\n        $Permissions = permissions\n        TableConditions($Name, \"\", JSONEncode($Permissions))\n    }\n\n    action {\n        PermTable($Name, JSONEncode($Permissions))\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'HonorNodeCondition', 'contract HonorNodeCondition {\n\tconditions {\n\t\tvar account_key int\n\t\taccount_key = AddressToId($account_id)\n\t\tif IsHonorNodeKey(account_key) {\n\t\t\treturn\n\t\t}\n\t\twarning \"HonorNodeCondition: Sorry, you do not have access to this action\"\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'Import', 'contract Import {\n    data {\n        Data string\n    }\n    conditions {\n        $ApplicationId = 0\n        var app_map map\n        app_map = DBFind(\"@1buffer_data\").Columns(\"value->app_name\").Where({\"key\": \"import_info\", \"account\": $account_id, \"ecosystem\": $ecosystem_id}).Row()\n        if app_map {\n            var app_id int ival string\n            ival = Str(app_map[\"value.app_name\"])\n            app_id = Int(DBFind(\"@1applications\").Columns(\"id\").Where({\"name\": ival, \"ecosystem\": $ecosystem_id}).One(\"id\"))\n            if app_id {\n                $ApplicationId = app_id\n            }\n        }\n    }\n    action {\n        var editors, creators map\n        editors[\"pages\"] = \"EditPage\"\n        editors[\"snippets\"] = \"EditSnippet\"\n        editors[\"menu\"] = \"EditMenu\"\n        editors[\"app_params\"] = \"EditAppParam\"\n        editors[\"languages\"] = \"EditLang\"\n        editors[\"contracts\"] = \"EditContract\"\n        editors[\"tables\"] = \"\" // nothing\n        creators[\"pages\"] = \"NewPage\"\n        creators[\"snippets\"] = \"NewSnippet\"\n        creators[\"menu\"] = \"NewMenu\"\n        creators[\"app_params\"] = \"NewAppParam\"\n        creators[\"languages\"] = \"NewLang\"\n        creators[\"contracts\"] = \"NewContract\"\n        creators[\"tables\"] = \"NewTable\"\n        var dataImport array\n        dataImport = JSONDecode($Data)\n        var i int\n        while i < Len(dataImport) {\n            var item cdata map type name string\n            cdata = dataImport[i]\n            if cdata {\n                cdata[\"ApplicationId\"] = $ApplicationId\n                type = cdata[\"Type\"]\n                name = cdata[\"Name\"]\n                // Println(Sprintf(\"import %v: %v\", type, cdata[\"Name\"]))\n                var tbl string\n                tbl = \"@1\" + Str(type)\n                if type == \"app_params\" {\n                    item = DBFind(tbl).Where({\"name\": name, \"ecosystem\": $ecosystem_id, \"app_id\": $ApplicationId}).Row()\n                } else {\n                    item = DBFind(tbl).Where({\"name\": name, \"ecosystem\": $ecosystem_id}).Row()\n                }\n                var contractName string\n                if item {\n                    contractName = editors[type]\n                    cdata[\"Id\"] = Int(item[\"id\"])\n                    if type == \"contracts\" {\n                        if item[\"conditions\"] == \"false\" {\n                            // ignore updating impossible\n                            contractName = \"\"\n                        }\n                    } elif type == \"menu\" {\n                        var menu menuItem string\n                        menu = Replace(item[\"value\"], \" \", \"\")\n                        menu = Replace(menu, \"\\n\", \"\")\n                        menu = Replace(menu, \"\\r\", \"\")\n                        menuItem = Replace(cdata[\"Value\"], \" \", \"\")\n                        menuItem = Replace(menuItem, \"\\n\", \"\")\n                        menuItem = Replace(menuItem, \"\\r\", \"\")\n                        if Contains(menu, menuItem) {\n                            // ignore repeated\n                            contractName = \"\"\n                        } else {\n                            cdata[\"Value\"] = item[\"value\"] + \"\\n\" + cdata[\"Value\"]\n                        }\n                    }\n                } else {\n                    contractName = creators[type]\n                }\n                if contractName != \"\" {\n                    CallContract(contractName, cdata)\n                }\n            }\n            i = i + 1\n        }\n        // Println(Sprintf(\"> time: %v\", $time))\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'ImportUpload', 'contract ImportUpload {\n    data {\n        Data file\n    }\n    conditions {\n        $Body = BytesToString($Data[\"Body\"])\n        $limit = 10 // data piece size of import\n    }\n    action {\n        // init buffer_data, cleaning old buffer\n        var initJson map\n        $import_id = Int(DBFind(\"@1buffer_data\").Where({\"account\": $account_id, \"key\": \"import\", \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $import_id {\n             DBUpdate(\"@1buffer_data\", $import_id, {\"value\": initJson})\n        } else {\n            $import_id = DBInsert(\"@1buffer_data\", {\"account\": $account_id, \"key\": \"import\", \"value\": initJson, \"ecosystem\": $ecosystem_id})\n        }\n        $info_id = Int(DBFind(\"@1buffer_data\").Where({\"account\": $account_id, \"key\": \"import_info\", \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $info_id {\n            DBUpdate(\"@1buffer_data\", $info_id, {\"value\": initJson})\n        } else {\n            $info_id = DBInsert(\"@1buffer_data\", {\"account\": $account_id, \"key\": \"import_info\", \"value\": initJson, \"ecosystem\": $ecosystem_id})\n        }\n        var input map arrData array\n        input = JSONDecode($Body)\n        arrData = input[\"data\"]\n        var pages_arr blocks_arr menu_arr parameters_arr languages_arr contracts_arr tables_arr array\n        // IMPORT INFO\n        var i lenArrData int item map\n        lenArrData = Len(arrData)\n        while i < lenArrData {\n            item = arrData[i]\n            if item[\"Type\"] == \"pages\" {\n                pages_arr = Append(pages_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"snippets\" {\n                blocks_arr = Append(blocks_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"menu\" {\n                menu_arr = Append(menu_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"app_params\" {\n                parameters_arr = Append(parameters_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"languages\" {\n                languages_arr = Append(languages_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"contracts\" {\n                contracts_arr = Append(contracts_arr, item[\"Name\"])\n            } elif item[\"Type\"] == \"tables\" {\n                tables_arr = Append(tables_arr, item[\"Name\"])\n            }\n            i = i + 1\n        }\n        var inf map\n        inf[\"app_name\"] = input[\"name\"]\n        inf[\"pages\"] = Join(pages_arr, \", \")\n        inf[\"pages_count\"] = Len(pages_arr)\n        inf[\"snippets\"] = Join(blocks_arr, \", \")\n        inf[\"blocks_count\"] = Len(blocks_arr)\n        inf[\"menu\"] = Join(menu_arr, \", \")\n        inf[\"menu_count\"] = Len(menu_arr)\n        inf[\"parameters\"] = Join(parameters_arr, \", \")\n        inf[\"parameters_count\"] = Len(parameters_arr)\n        inf[\"languages\"] = Join(languages_arr, \", \")\n        inf[\"languages_count\"] = Len(languages_arr)\n        inf[\"contracts\"] = Join(contracts_arr, \", \")\n        inf[\"contracts_count\"] = Len(contracts_arr)\n        inf[\"tables\"] = Join(tables_arr, \", \")\n        inf[\"tables_count\"] = Len(tables_arr)\n        if 0 == inf[\"pages_count\"] + inf[\"blocks_count\"] + inf[\"menu_count\"] + inf[\"parameters_count\"] + inf[\"languages_count\"] + inf[\"contracts_count\"] + inf[\"tables_count\"] {\n            warning \"Invalid or empty import file\"\n        }\n        // IMPORT DATA\n        // the contracts is imported in one piece, the rest is cut under the $limit\n        var sliced contracts array\n        i = 0\n        while i < lenArrData {\n            var items array l int item map\n            while l < $limit && (i + l < lenArrData) {\n                item = arrData[i + l]\n                if item[\"Type\"] == \"contracts\" {\n                    contracts = Append(contracts, item)\n                } else {\n                    items = Append(items, item)\n                }\n                l = l + 1\n            }\n            var batch map\n            batch[\"Data\"] = JSONEncode(items)\n            sliced = Append(sliced, batch)\n            i = i + $limit\n        }\n        if Len(contracts) > 0 {\n            var batch map\n            batch[\"Data\"] = JSONEncode(contracts)\n            sliced = Append(sliced, batch)\n        }\n        input[\"data\"] = sliced\n        // storing\n        DBUpdate(\"@1buffer_data\", $import_id, {\"value\": input})\n        DBUpdate(\"@1buffer_data\", $info_id, {\"value\": inf})\n        var name string\n        name = Str(input[\"name\"])\n        var cndns string\n        cndns = Str(input[\"conditions\"])\n        if !DBFind(\"@1applications\").Columns(\"id\").Where({\"name\": name, \"ecosystem\": $ecosystem_id}).One(\"id\") {\n            DBInsert(\"@1applications\", {\"name\": name, \"conditions\": cndns, \"ecosystem\": $ecosystem_id})\n        }\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewAppParam', 'contract NewAppParam {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"app_params\").Columns(\"id\").Where({\"name\":$Name}).One(\"id\") {\n            warning Sprintf( \"Application parameter %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"app_params\", {app_id: $ApplicationId, name: $Name, value: $Value,\n              conditions: $Conditions})\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewApplication', 'contract NewApplication {\n    data {\n        Name string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if Size($Name) == 0 {\n            warning \"Application name missing\"\n        }\n\n        if DBFind(\"applications\").Columns(\"id\").Where({name:$Name}).One(\"id\") {\n            warning Sprintf( \"Application %s already exists\", $Name)\n        }\n    }\n\n    action {\n        $result = DBInsert(\"applications\", {name: $Name,conditions: $Conditions})\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewBadBlock', 'contract NewBadBlock {\n\tdata {\n\t\tProducerNodeID int\n\t\tConsumerNodeID int\n\t\tBlockID int\n\t\tTimestamp int\n\t\tReason string\n\t}\n\taction {\n        DBInsert(\"@1bad_blocks\", {producer_node_id: $ProducerNodeID,consumer_node_id: $ConsumerNodeID,\n            block_id: $BlockID, \"timestamp block_time\": $Timestamp, reason: $Reason})\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewContract', 'contract NewContract {\n    data {\n        ApplicationId int\n        Value string\n        Conditions string\n        TokenEcosystem int \"optional\"\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        $contract_name = ContractName($Value)\n\n        if !$contract_name {\n            error \"must be the name\"\n        }\n\n        if !$TokenEcosystem {\n            $TokenEcosystem = 1\n        } else {\n            if !SysFuel($TokenEcosystem) {\n                warning Sprintf(\"Ecosystem %d is not system\", $TokenEcosystem)\n            }\n        }\n    }\n\n    action {\n        $result = CreateContract($contract_name, $Value, $Conditions, $TokenEcosystem, $ApplicationId)\n    }\n    func price() int {\n        return SysParamInt(\"contract_price\")\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewEcosystem', 'contract NewEcosystem {\n\tdata {\n\t\tName  string\n\t}\n\taction {\n\t\t$result = CreateEcosystem($key_id, $Name)\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewLang', 'contract NewLang {\n    data {\n        ApplicationId int\n        Name string\n        Trans string\n    }\n\n    conditions {\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"languages\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Language resource %s already exists\", $Name)\n        }\n\n        EvalCondition(\"parameters\", \"changing_language\", \"value\")\n    }\n\n    action {\n        CreateLanguage($Name, $Trans)\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewMenu', 'contract NewMenu {\n    data {\n        Name string\n        Value string\n        Title string \"optional\"\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if DBFind(\"menu\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Menu %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"menu\", {name:$Name,value: $Value, title: $Title, conditions: $Conditions})\n    }\n    func price() int {\n        return SysParamInt(\"menu_price\")\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewPage', 'contract NewPage {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Menu string\n        Conditions string\n        ValidateCount int \"optional\"\n        ValidateMode string \"optional\"\n    }\n    func preparePageValidateCount(count int) int {\n        var min, max int\n        min = Int(EcosysParam(\"min_page_validate_count\"))\n        max = Int(EcosysParam(\"max_page_validate_count\"))\n\n        if count < min {\n            count = min\n        } else {\n            if count > max {\n                count = max\n            }\n        }\n        return count\n    }\n\n    conditions {\n        ValidateCondition($Conditions,$ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"pages\").Columns(\"id\").Where({name: $Name}).One(\"id\") {\n            warning Sprintf( \"Page %s already exists\", $Name)\n        }\n\n        $ValidateCount = preparePageValidateCount($ValidateCount)\n\n        if $ValidateMode {\n            if $ValidateMode != \"1\" {\n                $ValidateMode = \"0\"\n            }\n        }\n    }\n\n    action {\n        DBInsert(\"pages\", {name: $Name,value: $Value, menu: $Menu,\n             validate_count:$ValidateCount,validate_mode: $ValidateMode,\n             conditions: $Conditions,app_id: $ApplicationId})\n    }\n    func price() int {\n        return SysParamInt(\"page_price\")\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewParameter', 'contract NewParameter {\n    data {\n        Name string\n        Value string\n        Conditions string\n    }\n    func warnEmpty(name value string) {\n        if Size(value) == 0 {\n            warning Sprintf(LangRes(\"@1x_parameter_empty\"),name)\n        }\n    }\n    conditions {\n        DeveloperCondition()\n\n        ValidateCondition($Conditions, $ecosystem_id)\n        $Name = TrimSpace($Name)\n        warnEmpty(\"Name\",$Name)\n        if DBFind(\"@1parameters\").Where({\"name\": $Name, \"ecosystem\": $ecosystem_id}).One(\"id\") {\n            warning Sprintf(LangRes(\"@1template_parameter_exists\"), $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"@1parameters\", {\"name\": $Name, \"value\": $Value, \"conditions\": $Conditions, \"ecosystem\": $ecosystem_id})\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewSnippet', 'contract NewSnippet {\n    data {\n        ApplicationId int\n        Name string\n        Value string\n        Conditions string\n    }\n\n    conditions {\n        ValidateCondition($Conditions, $ecosystem_id)\n\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n\n        if DBFind(\"snippets\").Columns(\"id\").Where({name:$Name}).One(\"id\") {\n            warning Sprintf( \"Block %s already exists\", $Name)\n        }\n    }\n\n    action {\n        DBInsert(\"snippets\", {name: $Name, value: $Value, conditions: $Conditions,\n              app_id: $ApplicationId})\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewTable', 'contract NewTable {\n    data {\n        ApplicationId int\n        Name string\n        Columns string\n        Permissions string\n    }\n    conditions {\n        if $ApplicationId == 0 {\n            warning \"Application id cannot equal 0\"\n        }\n        TableConditions($Name, $Columns, $Permissions)\n    }\n    \n    action {\n        CreateTable($Name, $Columns, $Permissions, $ApplicationId)\n    }\n    func price() int {\n        return SysParamInt(\"table_price\")\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NewUser', 'contract NewUser {\n    data {\n        NewPubkey string \"optional\"\n        Ecosystem int \"optional\"\n    }\n    func getEcosystem() {\n        $e_id = Int($Ecosystem)\n        if $e_id == 0 {\n            $e_id = $ecosystem_id\n        }\n        $eco = DBFind(\"@1ecosystems\").Where({\"id\": $e_id}).Row()\n        if !$eco {\n            warning Sprintf(LangRes(\"@1ecosystem_not_found\"), $e_id)\n        }\n    }\n    func canOpt() bool {\n        return $free_membership == 1 || $e_id == 1\n    }\n    conditions {\n        getEcosystem()\n        $newId = PubToID($NewPubkey)\n\n        if $newId == 0 {\n            warning LangRes(\"@1wrong_pub\")\n        }\n        if Size($NewPubkey) == 0 {\n            warning \"You did not enter the public key\"\n        }\n        $pub = HexToPub($NewPubkey)\n        $account = IdToAddress($newId)\n\n        $k = DBFind(\"@1keys\").Where({\"id\": $newId, \"account\": $account, \"ecosystem\": $e_id}).Row()\n\n        $free_membership = Int(DBFind(\"@1parameters\").Where({\"ecosystem\": $e_id, \"name\": \"free_membership\"}).One(\"value\"))\n    }\n\n    action {\n        var iscan bool\n        iscan = canOpt()\n        if !iscan {\n            warning Sprintf(LangRes(\"@1eco_no_open_new_user\"), $eco[\"name\"], $e_id)\n        }\n        if $k {\n            var kid int kpub string\n            kid = Int($k[\"id\"])\n            kpub = $k[\"pub\"]\n            if Size(kpub) != 0 {\n                warning Sprintf(LangRes(\"@1template_user_exists\"), IdToAddress($newId))\n            }\n            DBUpdateExt(\"@1keys\", {\"id\": kid, \"ecosystem\": $e_id}, {\"pub\": $pub})\n            $result = $account\n        }else{\n            DBInsert(\"@1keys\", {\"id\": $newId, \"account\": $account, \"pub\": $pub, \"ecosystem\": $e_id})\n            if !DBFind(\"@1keys\").Where({\"ecosystem\": 1, \"account\": $account}).Row() {\n                DBInsert(\"@1keys\", {\"id\": $newId, \"account\": $account, \"pub\": $pub, \"ecosystem\": 1})\n                var h map\n                $whiteHoleBalance = DBFind(\"@1keys\").Where({\"account\": $white_hole_account,\"ecosystem\":1}).Columns(\"amount\").One(\"amount\")\n                h[\"sender_id\"] =$white_hole_key\n                h[\"sender_balance\"] = $whiteHoleBalance\n                h[\"recipient_id\"] = $newId\n                h[\"comment\"] = \"New User\"\n                h[\"block_id\"] = $block\n                h[\"txhash\"] = $txhash\n                h[\"ecosystem\"] = 1\n                h[\"type\"] = 4\n                h[\"created_at\"] = $time\n                DBInsert(\"@1history\", h)\n            }\n            $result = $account\n        }\n        var h map\n        $whiteHoleBalance = DBFind(\"@1keys\").Where({\"account\": $white_hole_account,\"ecosystem\":$ecosystem_id}).Columns(\"amount\").One(\"amount\")\n        h[\"sender_id\"] =$white_hole_key\n        h[\"sender_balance\"] = $whiteHoleBalance\n        h[\"recipient_id\"] = $newId\n        h[\"comment\"] = \"New User\"\n        h[\"block_id\"] = $block\n        h[\"txhash\"] = $txhash\n        h[\"ecosystem\"] = $ecosystem_id\n        h[\"type\"] = 4\n        h[\"created_at\"] = $time\n        DBInsert(\"@1history\", h)\n    }\n}\n', '1', 'ContractConditions(\"NodeOwnerCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'NodeOwnerCondition', 'contract NodeOwnerCondition {\n\tconditions {\n        $raw_honor_nodes = SysParamString(\"honor_nodes\")\n        if Size($raw_honor_nodes) == 0 {\n            ContractConditions(\"MainCondition\")\n        } else {\n            $honor_nodes = JSONDecode($raw_honor_nodes)\n            var i int\n            while i < Len($honor_nodes) {\n                $fn = $honor_nodes[i]\n                if $fn[\"key_id\"] == $key_id {\n                    return true\n                }\n                i = i + 1\n            }\n            warning \"NodeOwnerCondition: Sorry, you do not have access to this action.\"\n        }\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'UnbindWallet', 'contract UnbindWallet {\n\tdata {\n\t\tId         int\n\t}\n\tconditions {\n\t\t$cur = DBRow(\"contracts\").Columns(\"id,conditions,wallet_id\").WhereId($Id)\n\t\tif !$cur {\n\t\t\terror Sprintf(\"Contract %d does not exist\", $Id)\n\t\t}\n\t\t\n\t\tEval($cur[\"conditions\"])\n\t\tif $key_id != Int($cur[\"wallet_id\"]) {\n\t\t\terror Sprintf(\"Wallet %d cannot deactivate the contract\", $key_id)\n\t\t}\n\t}\n\taction {\n\t\tUnbndWallet($Id, $ecosystem_id)\n\t}\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'UpdatePlatformParam', 'contract UpdatePlatformParam {\n     data {\n        Name string\n        Value string\n        Conditions string \"optional\"\n     }\n     conditions {\n         if !GetContractByName($Name){\n            warning \"System parameter not found\"\n         }\n     }\n     action {\n        var params map\n        params[\"Value\"] = $Value\n        CallContract($Name, params)\n        \n        DBUpdatePlatformParam($Name, $Value, $Conditions)\n     }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'UploadBinary', 'contract UploadBinary {\n    data {\n        ApplicationId int\n        Name string\n        Data bytes\n        DataMimeType string \"optional\"\n        MemberAccount string \"optional\"\n    }\n    conditions {\n        if Size($MemberAccount) > 0 {\n            $UserID = $MemberAccount\n        } else {\n            $UserID = $account_id\n        }\n        $Id = Int(DBFind(\"@1binaries\").Columns(\"id\").Where({\"app_id\": $ApplicationId, \n                \"account\": $UserID, \"name\": $Name, \"ecosystem\": $ecosystem_id}).One(\"id\"))\n        if $Id == 0 {\n            if $ApplicationId == 0 {\n                warning LangRes(\"@1aid_cannot_zero\")\n            }\n        }\n    }\n    action {\n        var hash string\n        hash = Hash($Data)\n        if $DataMimeType == \"\" {\n            $DataMimeType = \"application/octet-stream\"\n        }\n        if $Id != 0 {\n            DBUpdate(\"@1binaries\", $Id, {\"data\": $Data, \"hash\": hash, \"mime_type\": $DataMimeType})\n        } else {\n            $Id = DBInsert(\"@1binaries\", {\"app_id\": $ApplicationId, \"account\": $UserID,\n                \"name\": $Name, \"data\": $Data, \"hash\": hash, \"mime_type\": $DataMimeType, \"ecosystem\": $ecosystem_id})\n        }\n        $result = $Id\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1'),\n\t(next_id('1_contracts'), 'UploadFile', 'contract UploadFile {\n    data {\n        ApplicationId int\n        Data file\n        Name string \"optional\"\n    }\n    conditions {\n        if $Name == \"\" {\n            $Name = $Data[\"Name\"]\n        }\n        $Body = $Data[\"Body\"]\n        $DataMimeType = $Data[\"MimeType\"]\n    }\n    action {\n        $Id = @1UploadBinary(\"ApplicationId,Name,Data,DataMimeType\", $ApplicationId, $Name, $Body, $DataMimeType)\n        $result = $Id\n    }\n}\n', '1', 'ContractConditions(\"MainCondition\")', '1', '1');\n`"
  },
  {
    "path": "packages/migration/first_ecosys_pages_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar firstEcosystemPagesDataSQL = `INSERT INTO \"1_pages\" (id, name, value, menu, conditions, app_id, ecosystem) VALUES\n\t(next_id('1_pages'), 'notifications', '', 'default_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1'),\n\t(next_id('1_pages'), 'import_app', 'Div(content-wrapper){\n    DBFind(@1buffer_data).Columns(\"id,value->name,value->data\").Where({\"key\": import, \"account\": #account_id#, \"ecosystem\": #ecosystem_id#}).Vars(import)\n    DBFind(@1buffer_data).Columns(\"value->app_name,value->pages,value->pages_count,value->blocks,value->blocks_count,value->menu,value->menu_count,value->parameters,value->parameters_count,value->languages,value->languages_count,value->contracts,value->contracts_count,value->tables,value->tables_count\").Where({\"key\": import_info, \"account\": #account_id#, \"ecosystem\": #ecosystem_id#}).Vars(info)\n\n    SetTitle(\"Import - #info_value_app_name#\")\n    Data(data_info, \"DataName,DataCount,DataInfo\"){\n        Pages,\"#info_value_pages_count#\",\"#info_value_pages#\"\n        Blocks,\"#info_value_blocks_count#\",\"#info_value_blocks#\"\n        Menu,\"#info_value_menu_count#\",\"#info_value_menu#\"\n        Parameters,\"#info_value_parameters_count#\",\"#info_value_parameters#\"\n        Language resources,\"#info_value_languages_count#\",\"#info_value_languages#\"\n        Contracts,\"#info_value_contracts_count#\",\"#info_value_contracts#\"\n        Tables,\"#info_value_tables_count#\",\"#info_value_tables#\"\n    }\n    Div(breadcrumb){\n        Span(Class: text-muted, Body: \"Your data that you can import\")\n    }\n\n    Div(panel panel-primary){\n        ForList(data_info){\n            Div(list-group-item){\n                Div(row){\n                    Div(col-md-10 mc-sm text-left){\n                        Span(Class: text-bold, Body: \"#DataName#\")\n                    }\n                    Div(col-md-2 mc-sm text-right){\n                        If(#DataCount# > 0){\n                            Span(Class: text-bold, Body: \"(#DataCount#)\")\n                        }.Else{\n                            Span(Class: text-muted, Body: \"(0)\")\n                        }\n                    }\n                }\n                Div(row){\n                    Div(col-md-12 mc-sm text-left){\n                        If(#DataCount# > 0){\n                            Span(Class: h6, Body: \"#DataInfo#\")\n                        }.Else{\n                            Span(Class: text-muted h6, Body: \"Nothing selected\")\n                        }\n                    }\n                }\n            }\n        }\n        If(#import_id# > 0){\n            Div(list-group-item text-right){\n                VarAsIs(imp_data, \"#import_value_data#\")\n                Button(Body: \"Import\", Class: btn btn-primary, Page: @1apps_list).CompositeContract(@1Import, \"#imp_data#\")\n            }\n        }\n    }\n}', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1'),\n\t(next_id('1_pages'), 'import_upload', 'Div(content-wrapper){\n        SetTitle(\"Import\")\n        Div(breadcrumb){\n            Span(Class: text-muted, Body: \"Select payload that you want to import\")\n        }\n        Form(panel panel-primary){\n            Div(list-group-item){\n                Input(Name: Data, Type: file)\n            }\n            Div(list-group-item text-right){\n                Button(Body: \"Load\", Class: btn btn-primary, Contract: @1ImportUpload, Page: @1import_app)\n            }\n        }\n    }', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1');\n`\n"
  },
  {
    "path": "packages/migration/first_ecosys_snippets_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar firstEcosystemBlocksDataSQL = `INSERT INTO \"1_snippets\" (id, name, value, conditions, app_id, ecosystem) VALUES\n\t\t(next_id('1_snippets'), 'pager_header', '', 'ContractConditions(\"@1DeveloperCondition\")', '1', '1');\n`\n"
  },
  {
    "path": "packages/migration/first_ecosystem_schema.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\n// sqlFirstEcosystemSchema contains SQL queries for creating first ecosystem\nvar sqlFirstEcosystemSchema = `\n\t{{head \"1_ecosystems\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"info\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"fee_mode_info\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"is_valued\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"emission_amount\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"token_symbol\", \"string\", {\"null\": true, \"size\":255})\n\t\tt.Column(\"token_name\", \"string\", {\"null\": true, \"size\":255})\n\t\tt.Column(\"type_emission\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"type_withdraw\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"control_mode\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"digits\", \"bigint\", {\"default\": \"0\"})\n\t{{footer \"primary\"}}\n\n\t{{head \"1_platform_parameters\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t{{footer \"primary\" \"index(name)\"}}\n\n\t{{head \"1_delayed_contracts\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"contract\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"key_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"block_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"every_block\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"counter\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"high_rate\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"limit\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t{{footer \"primary\" \"index(block_id)\"}}\n\n\t{{head \"1_bad_blocks\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"producer_node_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"block_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"consumer_node_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"block_time\", \"timestamp\", {})\n\t\tt.Column(\"reason\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"deleted\", \"bigint\", {\"default\": \"0\"})\n\t{{footer \"primary\" }}\n\n\t{{head \"1_node_ban_logs\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"node_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"banned_at\", \"timestamp\", {})\n\t\tt.Column(\"ban_time\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"reason\", \"text\", {\"default\": \"\"})\n\t{{footer \"primary\" }}\n`\n\nvar sqlFirstEcosystemCommon = `\n\t{{head \"1_keys\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"pub\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"amount\", \"decimal(30)\", {\"default_raw\": \"'0' CHECK (amount >= 0)\"})\n\t\tt.Column(\"maxpay\", \"decimal(30)\", {\"default_raw\": \"'0' CHECK (maxpay >= 0)\"})\n\t\tt.Column(\"multi\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"blocked\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"account\", \"char(24)\", {})\n\t\tt.PrimaryKey(\"ecosystem\", \"id\")\n\t{{footer \"index(account)\" \"unique(ecosystem, account)\"}}\n\n\t{{head \"1_menu\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"title\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_pages\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"menu\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"validate_count\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"validate_mode\", \"character(1)\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_snippets\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_languages\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":100})\n\t\tt.Column(\"res\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_contracts\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"wallet_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"token_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem)\"}}\n\n\t{{head \"1_tables\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\": 100})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"columns\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_views\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\": 100})\n\t\tt.Column(\"columns\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"wheres\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_parameters\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, name)\" \"index(ecosystem, name)\"}}\n\n\t{{head \"1_history\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"sender_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"recipient_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"sender_balance\", \"decimal(30)\", {\"default\": \"0\"})\n\t\tt.Column(\"recipient_balance\", \"decimal(30)\", {\"default\": \"0\"})\n\t\tt.Column(\"amount\", \"decimal(30)\", {\"default\": \"0\"})\n\t\tt.Column(\"value_detail\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"comment\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"status\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"block_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"txhash\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"created_at\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"type\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem, sender_id)\"}}\n\tadd_index(\"1_history\", [\"ecosystem\", \"recipient_id\"], {})\n\tadd_index(\"1_history\", [\"block_id\", \"txhash\"], {})\n\n\t{{head \"1_sections\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"title\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"urlname\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"page\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"roles_access\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"status\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem)\"}}\n\n\t{{head \"1_members\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"member_name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"image_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"member_info\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"account\", \"char(24)\", {})\n\t{{footer \"primary\" \"index(ecosystem)\"}}\n\tadd_index(\"1_members\", [\"account\", \"ecosystem\"], {\"unique\": true})\n\n\t{{head \"1_roles\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"default_page\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"role_name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"role_type\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"creator\", \"jsonb\", {\"default\": \"{}\"})\n\t\tt.Column(\"date_created\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"date_deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"company_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"roles_access\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"image_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem, deleted)\"}}\n\tadd_index(\"1_roles\", [\"ecosystem\", \"role_type\"], {})\n\n\t{{head \"1_roles_participants\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"role\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"member\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"appointed\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"date_created\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"date_deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem)\"}}\n\n\t{{head \"1_notifications\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"recipient\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"sender\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"notification\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"page_params\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"processing_info\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"page_name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"date_created\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"date_start_processing\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"date_closed\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"closed\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem)\"}}\n\n\t{{head \"1_applications\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"uuid\", \"uuid\", {\"default\": \"00000000-0000-0000-0000-000000000000\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"deleted\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"index(ecosystem)\"}}\n\n\t{{head \"1_binaries\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"data\", \"bytea\", {\"default\": \"\"})\n\t\tt.Column(\"hash\", \"string\", {\"default\": \"\", \"size\": 64})\n\t\tt.Column(\"mime_type\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"account\", \"char(24)\", {})\n\t{{footer \"primary\"}}\n\tadd_index(\"1_binaries\", [\"account\", \"ecosystem\", \"app_id\", \"name\"], {\"unique\": true})\n\n\t{{head \"1_app_params\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"app_id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"value\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"conditions\", \"text\", {\"default\": \"\"})\n\t\tt.Column(\"permissions\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t{{footer \"primary\" \"unique(ecosystem, app_id, name)\" \"index(ecosystem,app_id,name)\"}}\n\n\t{{head \"1_buffer_data\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"key\", \"string\", {\"default\": \"\", \"size\": 255})\n\t\tt.Column(\"value\", \"jsonb\", {\"null\": true})\n\t\tt.Column(\"ecosystem\", \"bigint\", {\"default\": \"1\"})\n\t\tt.Column(\"account\", \"char(24)\", {})\n\t{{footer \"primary\" \"index(ecosystem)\"}}\n`\n"
  },
  {
    "path": "packages/migration/first_ecosystems_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar firstEcosystemDataSQL = `\nINSERT INTO \"1_ecosystems\" (\"id\", \"name\", \"is_valued\", \"digits\", \"token_symbol\", \"token_name\") VALUES \n\t(next_id('1_ecosystems'), 'platform ecosystem', '1', '{{.Digits}}', '{{.TokenSymbol}}', '{{.TokenName}}')\n;\n\nINSERT INTO \"1_applications\" (id, name, conditions, ecosystem) VALUES (next_id('1_applications'), 'System', 'ContractConditions(\"MainCondition\")', '1');\n`\n"
  },
  {
    "path": "packages/migration/first_tables_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar firstTablesDataSQL = `\nINSERT INTO \"1_tables\" (\"id\", \"name\", \"permissions\",\"columns\", \"conditions\") VALUES\n    (next_id('1_tables'), 'delayed_contracts',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1NewDelayedContract\\\")\",\n            \"update\": \"ContractAccess(\\\"@1CallDelayedContract\\\",\\\"@1EditDelayedContract\\\",\\\"@1CheckNodesBan\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"contract\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\",\n            \"key_id\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\",\n            \"block_id\": \"ContractAccess(\\\"@1CallDelayedContract\\\",\\\"@1EditDelayedContract\\\")\",\n            \"every_block\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\",\n            \"counter\": \"ContractAccess(\\\"@1CallDelayedContract\\\",\\\"@1EditDelayedContract\\\",\\\"@1CheckNodesBan\\\")\",\n            \"high_rate\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\",\n            \"limit\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\",\n            \"deleted\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditDelayedContract\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")'\n    ),\n    (next_id('1_tables'), 'ecosystems',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1NewEcosystem\\\")\",\n            \"update\": \"ContractAccess(\\\"@1EditEcosystemName\\\",\\\"@1VotingVesAccept\\\",\\\"@1EcManageInfo\\\",\\\"@1EcoFeeModeManage\\\",\\\"@1EditControlMode\\\",\\\"@1NewToken\\\",\\\"@1TeChange\\\",\\\"@1TeEmission\\\",\\\"@1TeBurn\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"ContractAccess(\\\"@1EditEcosystemName\\\")\",\n            \"info\": \"ContractAccess(\\\"@1EcManageInfo\\\")\",\n            \"digits\": \"ContractAccess(\\\"@1NewToken\\\")\",\n            \"fee_mode_info\": \"ContractAccess(\\\"@1EcoFeeModeManage\\\")\",\n            \"is_valued\": \"ContractAccess(\\\"@1VotingVesAccept\\\")\",\n            \"emission_amount\": \"ContractAccess(\\\"@1NewToken\\\",\\\"@1TeBurn\\\",\\\"@1TeEmission\\\")\",\n            \"token_symbol\": \"ContractAccess(\\\"@1NewToken\\\")\",\n            \"token_name\": \"ContractAccess(\\\"@1NewToken\\\")\",\n            \"type_emission\": \"ContractAccess(\\\"@1TeChange\\\",\\\"@1NewToken\\\")\",\n            \"type_withdraw\": \"ContractAccess(\\\"@1TeChange\\\",\\\"@1NewToken\\\")\",\n            \"control_mode\": \"ContractAccess(\\\"@1EditControlMode\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")'\n    ),\n    (next_id('1_tables'), 'platform_parameters',\n        '{\n            \"insert\": \"false\",\n            \"update\": \"ContractAccess(\\\"@1UpdatePlatformParam\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"value\": \"ContractAccess(\\\"@1UpdatePlatformParam\\\")\",\n            \"name\": \"false\",\n            \"conditions\": \"ContractAccess(\\\"@1UpdatePlatformParam\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")'\n    ),\n    (next_id('1_tables'), 'bad_blocks',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1NewBadBlock\\\")\",\n            \"update\": \"ContractAccess(\\\"@1NewBadBlock\\\", \\\"@1CheckNodesBan\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"block_id\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"producer_node_id\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"consumer_node_id\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"block_time\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"reason\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"deleted\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")'\n    ),\n    (next_id('1_tables'), 'node_ban_logs',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"update\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"node_id\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"banned_at\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"ban_time\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\",\n            \"reason\": \"ContractAccess(\\\"@1CheckNodesBan\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")'\n    ),\n    (next_id('1_tables'), 'time_zones',\n        '{\n            \"insert\": \"false\",\n            \"update\": \"false\",\n            \"new_column\": \"false\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"offset\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")'\n    );\n`\n"
  },
  {
    "path": "packages/migration/gen/contracts.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"html/template\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/BurntSushi/toml\"\n)\n\nconst (\n\text = \".sim\"\n\n\tdefaultPackageName = \"migration\"\n)\n\nvar (\n\tscenarios = []scenario{\n\t\t{\n\t\t\tSource:    []string{\"./contracts/ecosystem\"},\n\t\t\tDest:      \"./contracts_data.go\",\n\t\t\tVariable:  \"contractsDataSQL\",\n\t\t\tEcosystem: \"{{.Ecosystem}}\",\n\t\t\tOwner:     \"{{.Owner}}\",\n\t\t},\n\t\t{\n\t\t\tSource:    []string{\"./contracts/first_ecosystem\"},\n\t\t\tDest:      \"./first_ecosys_contracts_data.go\",\n\t\t\tVariable:  \"firstEcosystemContractsSQL\",\n\t\t\tEcosystem: \"1\",\n\t\t\tOwner:     \"{{.Owner}}\",\n\t\t},\n\t\t{\n\t\t\tSource:    []string{\"./contracts/common\", \"./contracts/first_ecosystem\", \"./contracts/clb\"},\n\t\t\tDest:      \"./clb/clb_data_contracts.go\",\n\t\t\tVariable:  \"contractsDataSQL\",\n\t\t\tEcosystem: \"%[1]d\",\n\t\t},\n\t}\n\n\tpropPrefix = []byte(\"// +prop \")\n)\n\ntype scenario struct {\n\tSource    []string\n\tDest      string\n\tVariable  string\n\tEcosystem string\n\tOwner     string\n}\n\ntype contract struct {\n\tName       string\n\tSource     template.HTML\n\tConditions template.HTML\n\tAppID      string\n}\n\ntype meta struct {\n\tAppID      string\n\tConditions string\n}\n\nvar fns = template.FuncMap{\n\t\"add\": func(a, b int) int {\n\t\treturn a + b\n\t},\n}\n\nvar contractsTemplate = template.Must(template.New(\"\").Funcs(fns).Parse(`// Code generated by go generate; DO NOT EDIT.\n\npackage {{ .Package }}\n\nvar {{ .Variable }} = ` + \"`\" + `\nINSERT INTO \"1_contracts\" (id, name, value, token_id, conditions, app_id{{if .Owner }}, wallet_id{{end}}, ecosystem)\nVALUES\n{{- $last := add (len .Contracts) -1}}\n{{- range $i, $item := .Contracts}}\n\t(next_id('1_contracts'), '{{ $item.Name }}', '{{ $item.Source }}', '{{ $.Ecosystem }}', '{{ $item.Conditions }}', '{{ $item.AppID }}'{{if $.Owner }}, {{ $.Owner }}{{end}}, '{{ $.Ecosystem }}'){{if eq $last $i}};{{else}},{{end}}\n{{- end}}\n` + \"`\"))\n\nfunc main() {\n\tfor _, s := range scenarios {\n\t\tif err := generate(s); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n}\n\nfunc escape(data string) template.HTML {\n\t//data = strings.Replace(data, `%`, `%%`, -1)\n\tdata = strings.Replace(data, `'`, `''`, -1)\n\tdata = strings.Replace(data, \"`\", \"` + \\\"`\\\" + `\", -1)\n\treturn template.HTML(data)\n}\n\nfunc loadSource(srcPath string) (*contract, error) {\n\tfile, err := os.Open(srcPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer file.Close()\n\n\tprops := make([]byte, 0)\n\tdata := make([]byte, 0)\n\n\tscan := bufio.NewScanner(file)\n\tfor scan.Scan() {\n\t\tline := scan.Bytes()\n\t\tif bytes.HasPrefix(line, propPrefix) {\n\t\t\tprops = append(append(props, line[len(propPrefix):]...), '\\n')\n\t\t} else {\n\t\t\tdata = append(append(data, line...), '\\n')\n\t\t}\n\t}\n\n\tm := &meta{}\n\tif err = toml.Unmarshal(props, m); err != nil {\n\t\treturn nil, err\n\t}\n\n\tname := filepath.Base(srcPath)\n\text := filepath.Ext(srcPath)\n\n\treturn &contract{\n\t\tName:       name[0 : len(name)-len(ext)],\n\t\tSource:     escape(string(data)),\n\t\tConditions: escape(m.Conditions),\n\t\tAppID:      m.AppID,\n\t}, nil\n}\n\nfunc loadSources(srcPaths []string) ([]*contract, error) {\n\tsources := make([]*contract, 0)\n\n\tfor _, srcPath := range srcPaths {\n\t\terr := filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error {\n\t\t\tif filepath.Ext(path) != ext {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tsource, err := loadSource(path)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsources = append(sources, source)\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tsort.Slice(sources, func(i, j int) bool {\n\t\treturn sources[i].Name < sources[j].Name\n\t})\n\n\treturn sources, nil\n}\n\nfunc generate(s scenario) error {\n\tsources, err := loadSources(s.Source)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfile, err := os.Create(s.Dest)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer file.Close()\n\n\tpkg := filepath.Base(filepath.Dir(s.Dest))\n\tif pkg == \".\" {\n\t\tpkg = defaultPackageName\n\t}\n\n\treturn contractsTemplate.Execute(file, map[string]any{\n\t\t\"Package\":   pkg,\n\t\t\"Variable\":  s.Variable,\n\t\t\"Ecosystem\": s.Ecosystem,\n\t\t\"Owner\":     nil,\n\t\t\"Contracts\": sources,\n\t})\n}\n"
  },
  {
    "path": "packages/migration/gen/contracts_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"html/template\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestEscape(t *testing.T) {\n\tvar cases = []struct {\n\t\tSource   string\n\t\tExpected template.HTML\n\t}{\n\t\t{`'test'`, `''test''`},\n\t\t{\"`test`\", \"` + \\\"`\\\" + `test` + \\\"`\\\" + `\"},\n\t\t{`100%`, `100%%`},\n\t}\n\n\tfor _, v := range cases {\n\t\tassert.Equal(t, v.Expected, escape(v.Source))\n\t}\n}\n\nfunc tempContract(appID int, conditions, value string) (string, error) {\n\tfile, err := os.CreateTemp(\"\", \"contract\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer file.Close()\n\n\tfile.Write([]byte(fmt.Sprintf(`// +prop AppID = %d\n// +prop Conditions = '%s'\n%s`, appID, conditions, value)))\n\n\treturn file.Name(), nil\n}\n\nfunc TestLoadSource(t *testing.T) {\n\tvalue := \"contract Test {}\"\n\n\tpath, err := tempContract(5, \"true\", value)\n\tassert.NoError(t, err)\n\n\tsource, err := loadSource(path)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, &contract{\n\t\tName:       filepath.Base(path),\n\t\tSource:     template.HTML(value + \"\\n\"),\n\t\tConditions: template.HTML(\"true\"),\n\t\tAppID:      5,\n\t}, source)\n}\n"
  },
  {
    "path": "packages/migration/keys_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nvar keysDataSQL = `\nINSERT INTO \"1_keys\" (id, account, pub, blocked, ecosystem) \nVALUES \n\t(` + consts.GuestKey + `, '` + consts.GuestAddress + `', decode('` + consts.GuestPublic + `', 'hex'), 1, '{{.Ecosystem}}'),\n\t(` + strconv.FormatInt(converter.HoleAddrMap[converter.BlackHoleAddr].K, 10) + `, '` + converter.HoleAddrMap[converter.BlackHoleAddr].S + `', decode('', 'hex'), 1, '{{.Ecosystem}}'),\n\t(` + strconv.FormatInt(converter.HoleAddrMap[converter.WhiteHoleAddr].K, 10) + `, '` + converter.HoleAddrMap[converter.WhiteHoleAddr].S + `', decode('', 'hex'), 1, '{{.Ecosystem}}');\n`\n"
  },
  {
    "path": "packages/migration/members_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nvar membersDataSQL = `\n\tINSERT INTO \"1_members\" (\"id\", \"account\", \"member_name\", \"ecosystem\") \n\tVALUES\n\t\t(next_id('1_members'), '{{.Account}}', 'founder', '{{.Ecosystem}}'),\n\t\t(next_id('1_members'), '` + consts.GuestAddress + `', 'guest', '{{.Ecosystem}}'),\n\t\t(next_id('1_members'), '` + converter.HoleAddrMap[converter.BlackHoleAddr].S + `', 'black_hole', '{{.Ecosystem}}'),\n\t\t(next_id('1_members'), '` + converter.HoleAddrMap[converter.WhiteHoleAddr].S + `', 'white_hole', '{{.Ecosystem}}');\n`\n"
  },
  {
    "path": "packages/migration/menu_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar menuDataSQL = `INSERT INTO \"1_menu\" (id, name, value, conditions, ecosystem) VALUES\n(next_id('1_menu'), 'developer_menu', 'MenuItem(Title:\"Import\", Page:@1import_upload, Icon:\"icon-cloud-upload\")', 'ContractAccess(\"@1EditMenu\")','{{.Ecosystem}}');\n`\n"
  },
  {
    "path": "packages/migration/migration.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/migration/updates\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\teVer = `Wrong version %s`\n)\n\nvar migrations = []*migration{\n\t// Initial schema\n\t{\"0.0.1\", migrationInitialTables, true},\n\t{\"0.0.2\", migrationInitialSchema, false},\n}\n\nvar updateMigrations = []*migration{\n\t{\"0.0.3\", updates.MigrationUpdatePriceExec, false},\n\t{\"0.0.4\", updates.MigrationUpdateAccessExec, false},\n\t{\"0.0.5\", updates.MigrationUpdatePriceCreateExec, false},\n}\n\ntype migration struct {\n\tversion  string\n\tdata     string\n\ttemplate bool\n}\n\ntype database interface {\n\tCurrentVersion() (string, error)\n\tApplyMigration(string, string) error\n}\n\nfunc compareVer(a, b string) (int, error) {\n\tvar (\n\t\tav, bv []string\n\t\tai, bi int\n\t\terr    error\n\t)\n\tif av = strings.Split(a, `.`); len(av) != 3 {\n\t\treturn 0, fmt.Errorf(eVer, a)\n\t}\n\tif bv = strings.Split(b, `.`); len(bv) != 3 {\n\t\treturn 0, fmt.Errorf(eVer, b)\n\t}\n\tfor i, v := range av {\n\t\tif ai, err = strconv.Atoi(v); err != nil {\n\t\t\treturn 0, fmt.Errorf(eVer, a)\n\t\t}\n\t\tif bi, err = strconv.Atoi(bv[i]); err != nil {\n\t\t\treturn 0, fmt.Errorf(eVer, b)\n\t\t}\n\t\tif ai < bi {\n\t\t\treturn -1, nil\n\t\t}\n\t\tif ai > bi {\n\t\t\treturn 1, nil\n\t\t}\n\t}\n\treturn 0, nil\n}\n\nfunc migrate(db database, appVer string, migrations []*migration) error {\n\tdbVerString, err := db.CurrentVersion()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"err\": err}).Errorf(\"parse version\")\n\t\treturn err\n\t}\n\n\tif cmp, err := compareVer(dbVerString, appVer); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.MigrationError, \"err\": err}).Errorf(\"parse version\")\n\t\treturn err\n\t} else if cmp >= 0 {\n\t\treturn nil\n\t}\n\n\tfor _, m := range migrations {\n\t\tif cmp, err := compareVer(dbVerString, m.version); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.MigrationError, \"err\": err}).Errorf(\"parse version\")\n\t\t\treturn err\n\t\t} else if cmp >= 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif m.template {\n\t\t\tm.data, err = sqlConvert([]string{m.data})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\terr = db.ApplyMigration(m.version, m.data)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"err\": err, \"version\": m.version}).Errorf(\"apply migration\")\n\t\t\treturn err\n\t\t}\n\n\t\tlog.WithFields(log.Fields{\"version\": m.version}).Debug(\"apply migration\")\n\t}\n\n\treturn nil\n}\n\nfunc runMigrations(db database, migrationList []*migration) error {\n\treturn migrate(db, consts.VERSION, migrationList)\n}\n\n// InitMigrate applies initial migrations\nfunc InitMigrate(db database) error {\n\tmig := migrations\n\tif conf.Config.IsSubNode() {\n\t\t//mig = append(mig, migrationsSub)\n\t}\n\tif conf.Config.IsSupportingCLB() {\n\t\t//mig = append(mig, migrationsCLB)\n\t}\n\treturn runMigrations(db, mig)\n}\n\n// UpdateMigrate applies update migrations\nfunc UpdateMigrate(db database) error {\n\treturn runMigrations(db, updateMigrations)\n}\n"
  },
  {
    "path": "packages/migration/migration_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nimport (\n\t\"testing\"\n)\n\ntype dbMock struct {\n\tversions []string\n}\n\nfunc (dbm *dbMock) CurrentVersion() (string, error) {\n\treturn dbm.versions[len(dbm.versions)-1], nil\n}\n\nfunc (dbm *dbMock) ApplyMigration(version, query string) error {\n\tdbm.versions = append(dbm.versions, version)\n\treturn nil\n}\n\nfunc createDBMock(version string) *dbMock {\n\treturn &dbMock{versions: []string{version}}\n}\n\nfunc TestMockMigration(t *testing.T) {\n\terr := migrate(createDBMock(\"error version\"), ``, nil)\n\tif err.Error() != \"Wrong version error version\" {\n\t\tt.Error(err)\n\t}\n\n\tappVer := \"0.0.2\"\n\n\terr = migrate(createDBMock(\"0\"), appVer, []*migration{{version: \"error version\", data: \"\"}})\n\tif err.Error() != \"Wrong version 0\" {\n\t\tt.Error(err)\n\t}\n\n\tdb := createDBMock(\"0.0.0\")\n\terr = migrate(\n\t\tdb, appVer,\n\t\t[]*migration{\n\t\t\t{version: \"0.0.1\", data: \"\"},\n\t\t\t{version: \"0.0.2\", data: \"\"},\n\t\t},\n\t)\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tif v, _ := db.CurrentVersion(); v != \"0.0.2\" {\n\t\tt.Errorf(\"current version expected 0.0.2 get %s\", v)\n\t}\n\n\tdb = createDBMock(\"0.0.2\")\n\terr = migrate(db, appVer, []*migration{\n\t\t{version: \"0.0.3\", data: \"\"},\n\t})\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\tif v, _ := db.CurrentVersion(); v != \"0.0.2\" {\n\t\tt.Errorf(\"current version expected 0.0.2 get %s\", v)\n\t}\n}\n"
  },
  {
    "path": "packages/migration/pages_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar pagesDataSQL = `INSERT INTO \"1_pages\" (id, name, value, menu, conditions, app_id, ecosystem) VALUES\n\t(next_id('1_pages'), 'developer_index', '', 'developer_menu', 'ContractConditions(\"@1DeveloperCondition\")', '{{.AppID}}', '{{.Ecosystem}}');`\n"
  },
  {
    "path": "packages/migration/parameters_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar parametersDataSQL = `\nINSERT INTO \"1_parameters\" (\"id\",\"name\", \"value\", \"conditions\", \"ecosystem\") VALUES\n\t(next_id('1_parameters'),'founder_account', '{{.Wallet}}', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'new_table', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_tables', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_language', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_page', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_menu', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_contracts', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_parameters', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_app_params', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'changing_snippets', 'ContractConditions(\"DeveloperCondition\")', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'max_sum', '1000000', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'print_stylesheet', 'body {\n\t\t  /* You can define your custom styles here or create custom CSS rules */\n\t}', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'min_page_validate_count', '1', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}'),\n\t(next_id('1_parameters'),'max_page_validate_count', '6', 'ContractConditions(\"DeveloperCondition\")', '{{.Ecosystem}}');\n`\n"
  },
  {
    "path": "packages/migration/platform_parameters_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar platformParametersDataSQL = `\nINSERT INTO \"1_platform_parameters\" (\"id\",\"name\", \"value\", \"conditions\") VALUES \n\t(next_id('1_platform_parameters'),'default_ecosystem_page', 'If(#ecosystem_id# > 1){Include(@1welcome)}', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'default_ecosystem_menu', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'default_ecosystem_contract', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'gap_between_blocks', '2', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'rollback_blocks', '60', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'honor_nodes', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'number_of_nodes', '101', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_block_size', '67108864', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_tx_size', '33554432', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_tx_block', '5000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_columns', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_indexes', '5', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_tx_block_per_user', '5000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_fuel_tx', '20000000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_fuel_block', '200000000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'taxes_size', '3', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'taxes_wallet', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'fuel_rate', '[[\"1\",\"1000000\"]]', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'max_block_generation_time', '2000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'incorrect_blocks_per_day','10','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'node_ban_time','86400000','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'node_ban_time_local','1800000','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_tx_size', '15', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'test','false','false'),\n\t(next_id('1_platform_parameters'),'price_tx_data', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'private_blockchain', '1', 'false'),\n\t(next_id('1_platform_parameters'),'pay_free_contract', '@1CallDelayedContract,@1CheckNodesBan,@1NewUser', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n    (next_id('1_platform_parameters'),'local_node_ban_time', '60', 'ContractAccess(\"@1UpdatePlatformParam\")');\n`\n"
  },
  {
    "path": "packages/migration/sections_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar sectionsDataSQL = `\nINSERT INTO \"1_sections\" (\"id\",\"title\",\"urlname\",\"page\",\"roles_access\", \"status\", \"ecosystem\") VALUES\n(next_id('1_sections'), 'Home', 'home', 'default_page', '[]', 2, '{{.Ecosystem}}'),\n(next_id('1_sections'), 'Developer', 'developer', 'developer_index', '[]', 1, '{{.Ecosystem}}');\n`\n"
  },
  {
    "path": "packages/migration/tables_data.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar tablesDataSQL = `INSERT INTO \"1_tables\" (\"id\", \"name\", \"permissions\",\"columns\", \"conditions\", \"ecosystem\") VALUES\n    (next_id('1_tables'), 'contracts',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{    \n            \"name\": \"false\",\n            \"value\": \"ContractAccess(\\\"@1EditContract\\\")\",\n            \"wallet_id\": \"ContractAccess(\\\"@1BindWallet\\\", \\\"@1UnbindWallet\\\")\",\n            \"token_id\": \"ContractAccess(\\\"@1EditContract\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditContract\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"app_id\": \"ContractAccess(\\\"@1ItemChangeAppId\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'keys',\n        '{\n            \"insert\": \"true\",\n            \"update\": \"ContractAccess(\\\"@1TokensTransfer\\\",\\\"@1TokensLockoutMember\\\",\\\"@1NewToken\\\",\\\"@1TeBurn\\\",\\\"@1ProfileEdit\\\",\\\"@1NewUser\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"pub\": \"ContractAccess(\\\"@1NewUser\\\")\",\n            \"amount\": \"ContractAccess(\\\"@1TokensTransfer\\\",\\\"@1NewToken\\\",\\\"@1TeBurn\\\",\\\"@1ProfileEdit\\\")\",\n            \"maxpay\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"deleted\": \"ContractAccess(\\\"@1DeleteMember\\\")\",\n            \"blocked\": \"ContractAccess(\\\"@1TokensLockoutMember\\\")\",\n            \"account\": \"false\",\n            \"ecosystem\": \"false\",\n            \"multi\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'history',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1TokensTransfer\\\",\\\"@1NewUser\\\",\\\"@1NewToken\\\",\\\"@1TeBurn\\\",\\\"@1ProfileEdit\\\",\\\"@1MembershipRequest\\\",\\\"@1MembershipDecide\\\",\\\"@1MembershipAdd\\\",\\\"@1DeleteMember\\\")\",\n            \"update\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"sender_id\": \"false\",\n            \"recipient_id\": \"false\",\n            \"sender_balance\": \"false\",\n            \"recipient_balance\": \"false\",\n            \"amount\":  \"false\",\n            \"value_detail\":  \"false\",\n            \"comment\": \"false\",\n            \"status\": \"false\",\n            \"block_id\":  \"false\",\n            \"txhash\": \"false\",\n            \"ecosystem\": \"false\",\n            \"type\": \"false\",\n            \"created_at\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'languages',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"ContractAccess(\\\"@1EditLang\\\")\",\n            \"res\": \"ContractAccess(\\\"@1EditLang\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditLang\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'menu',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"value\": \"ContractAccess(\\\"@1EditMenu\\\",\\\"@1AppendMenu\\\")\",\n            \"title\": \"ContractAccess(\\\"@1EditMenu\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditMenu\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'pages',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"value\": \"ContractAccess(\\\"@1EditPage\\\",\\\"@1AppendPage\\\")\",\n            \"menu\": \"ContractAccess(\\\"@1EditPage\\\")\",\n            \"validate_count\": \"ContractAccess(\\\"@1EditPage\\\")\",\n            \"validate_mode\": \"ContractAccess(\\\"@1EditPage\\\")\",\n            \"app_id\": \"ContractAccess(\\\"@1ItemChangeAppId\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditPage\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'snippets',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"value\": \"ContractAccess(\\\"@1EditSnippet\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditSnippet\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"app_id\": \"ContractAccess(\\\"@1ItemChangeAppId\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'members',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1ProfileEdit\\\")\",\n            \"update\": \"ContractAccess(\\\"@1ProfileEdit\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"image_id\": \"ContractAccess(\\\"@1ProfileEdit\\\")\",\n            \"member_info\": \"ContractAccess(\\\"@1ProfileEdit\\\")\",\n            \"member_name\": \"false\",\n            \"account\":\"false\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'roles',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1RolesCreate\\\",\\\"@1RolesInstall\\\")\",\n            \"update\": \"ContractAccess(\\\"@1RolesAccessManager\\\",\\\"@1RolesDelete\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"default_page\": \"false\",\n            \"creator\": \"false\",\n            \"deleted\": \"ContractAccess(\\\"@1RolesDelete\\\")\",\n            \"company_id\": \"false\",\n            \"date_deleted\": \"ContractAccess(\\\"@1RolesDelete\\\")\",\n            \"image_id\": \"false\",\n            \"role_name\": \"false\",\n            \"date_created\": \"false\",\n            \"roles_access\": \"ContractAccess(\\\"@1RolesAccessManager\\\")\",\n            \"role_type\": \"false\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'roles_participants',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1RolesAssign\\\",\\\"@1VotingDecisionCheck\\\",\\\"@1RolesInstall\\\")\",\n            \"update\": \"ContractAccess(\\\"@1RolesUnassign\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"deleted\": \"ContractAccess(\\\"@1RolesUnassign\\\")\",\n            \"date_deleted\": \"ContractAccess(\\\"@1RolesUnassign\\\")\",\n            \"member\": \"false\",\n            \"role\": \"false\",\n            \"date_created\": \"false\",\n            \"appointed\": \"false\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'notifications',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1NotificationsSend\\\", \\\"@1CheckNodesBan\\\", \\\"@1NotificationsBroadcast\\\")\",\n            \"update\": \"ContractAccess(\\\"@1NotificationsSend\\\", \\\"@1NotificationsClose\\\", \\\"@1NotificationsProcess\\\", \\\"@1NotificationsUpdateParams\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"date_closed\": \"ContractAccess(\\\"@1NotificationsClose\\\")\",\n            \"sender\": \"false\",\n            \"processing_info\": \"ContractAccess(\\\"@1NotificationsClose\\\",\\\"@1NotificationsProcess\\\")\",\n            \"date_start_processing\": \"ContractAccess(\\\"@1NotificationsClose\\\",\\\"@1NotificationsProcess\\\")\",\n            \"notification\": \"false\",\n            \"page_name\": \"false\",\n            \"page_params\": \"ContractAccess(\\\"@1NotificationsUpdateParams\\\")\",\n            \"closed\": \"ContractAccess(\\\"@1NotificationsClose\\\")\",\n            \"date_created\": \"false\",\n            \"recipient\": \"false\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'sections',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"title\": \"ContractAccess(\\\"@1EditSection\\\")\",\n            \"urlname\": \"ContractAccess(\\\"@1EditSection\\\")\",\n            \"page\": \"ContractAccess(\\\"@1EditSection\\\")\",\n            \"roles_access\": \"ContractAccess(\\\"@1SectionRoles\\\")\",\n            \"status\": \"ContractAccess(\\\"@1EditSection\\\",\\\"@1NewSection\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'applications',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"uuid\": \"false\",\n            \"conditions\": \"ContractAccess(\\\"@1EditApplication\\\")\",\n            \"deleted\": \"ContractAccess(\\\"@1DelApplication\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'binaries',\n        '{\n            \"insert\": \"ContractAccess(\\\"@1UploadBinary\\\")\",\n            \"update\": \"ContractAccess(\\\"@1UploadBinary\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"hash\": \"ContractAccess(\\\"@1UploadBinary\\\")\",\n            \"account\": \"false\",\n            \"data\": \"ContractAccess(\\\"@1UploadBinary\\\")\",\n            \"name\": \"false\",\n            \"app_id\": \"false\",\n            \"ecosystem\": \"false\",\n            \"mime_type\": \"ContractAccess(\\\"@1UploadBinary\\\")\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'parameters',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractAccess(\\\"@1EditParameter\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"value\": \"ContractAccess(\\\"@1EditParameter\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditParameter\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'app_params',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"ContractAccess(\\\"@1EditAppParam\\\")\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"app_id\": \"ContractAccess(\\\"@1ItemChangeAppId\\\")\",\n            \"name\": \"false\",\n            \"value\": \"ContractAccess(\\\"@1EditAppParam\\\")\",\n            \"conditions\": \"ContractAccess(\\\"@1EditAppParam\\\")\",\n            \"permissions\": \"ContractConditions(\\\"@1MainCondition\\\")\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n    (next_id('1_tables'), 'buffer_data',\n        '{\n            \"insert\": \"true\",\n            \"update\": \"true\",\n            \"new_column\": \"ContractConditions(\\\"@1MainCondition\\\")\"\n        }',\n        '{\n            \"key\": \"false\",\n            \"value\": \"true\",\n            \"account\": \"false\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    ),\n\t(next_id('1_tables'), 'views',\n        '{\n            \"insert\": \"ContractConditions(\\\"DeveloperCondition\\\")\",\n            \"update\": \"false\",\n            \"new_column\": \"false\"\n        }',\n        '{\n            \"name\": \"false\",\n            \"columns\": \"false\",\n            \"wheres\": \"false\",\n            \"permissions\": \"true\",\n            \"conditions\": \"true\",\n            \"app_id\": \"false\",\n            \"ecosystem\": \"false\"\n        }',\n        'ContractConditions(\"@1MainCondition\")', '{{.Ecosystem}}'\n    );\n`\n"
  },
  {
    "path": "packages/migration/timezones.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage migration\n\nvar sqlTimeZonesSQL = `\n\t{{head \"1_time_zones\"}}\n\t\tt.Column(\"id\", \"bigint\", {\"default\": \"0\"})\n\t\tt.Column(\"name\", \"string\", {\"default\": \"\", \"size\":255})\n\t\tt.Column(\"offset\", \"string\", {\"default\": \"\", \"size\":6})\n\t{{footer \"primary\" \"unique(name)\"}}\n`\n\nvar timeZonesSQL = `\nINSERT INTO \"1_time_zones\" VALUES \n(next_id('1_time_zones'), 'Africa/Abidjan', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Accra', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Addis_Ababa', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Algiers', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Asmara', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Bamako', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Bangui', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Banjul', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Bissau', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Blantyre', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Brazzaville', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Bujumbura', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Cairo', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Casablanca', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Ceuta', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Conakry', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Dakar', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Dar_es_Salaam', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Djibouti', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Douala', '+01:00'),\n(next_id('1_time_zones'), 'Africa/El_Aaiun', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Freetown', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Gaborone', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Harare', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Johannesburg', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Juba', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Kampala', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Khartoum', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Kigali', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Kinshasa', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Lagos', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Libreville', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Lome', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Luanda', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Lubumbashi', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Lusaka', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Malabo', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Maputo', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Maseru', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Mbabane', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Mogadishu', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Monrovia', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Nairobi', '+03:00'),\n(next_id('1_time_zones'), 'Africa/Ndjamena', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Niamey', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Nouakchott', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Ouagadougou', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Porto-Novo', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Sao_Tome', 'UTC'),\n(next_id('1_time_zones'), 'Africa/Tripoli', '+02:00'),\n(next_id('1_time_zones'), 'Africa/Tunis', '+01:00'),\n(next_id('1_time_zones'), 'Africa/Windhoek', '+02:00'),\n(next_id('1_time_zones'), 'America/Adak', '-09:00'),\n(next_id('1_time_zones'), 'America/Anchorage', '-08:00'),\n(next_id('1_time_zones'), 'America/Anguilla', '-04:00'),\n(next_id('1_time_zones'), 'America/Antigua', '-04:00'),\n(next_id('1_time_zones'), 'America/Araguaina', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Buenos_Aires', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Catamarca', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Cordoba', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Jujuy', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/La_Rioja', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Mendoza', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Rio_Gallegos', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Salta', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/San_Juan', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/San_Luis', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Tucuman', '-03:00'),\n(next_id('1_time_zones'), 'America/Argentina/Ushuaia', '-03:00'),\n(next_id('1_time_zones'), 'America/Aruba', '-04:00'),\n(next_id('1_time_zones'), 'America/Asuncion', '-04:00'),\n(next_id('1_time_zones'), 'America/Atikokan', '-05:00'),\n(next_id('1_time_zones'), 'America/Bahia', '-03:00'),\n(next_id('1_time_zones'), 'America/Bahia_Banderas', '-05:00'),\n(next_id('1_time_zones'), 'America/Barbados', '-04:00'),\n(next_id('1_time_zones'), 'America/Belem', '-03:00'),\n(next_id('1_time_zones'), 'America/Belize', '-06:00'),\n(next_id('1_time_zones'), 'America/Blanc-Sablon', '-04:00'),\n(next_id('1_time_zones'), 'America/Boa_Vista', '-04:00'),\n(next_id('1_time_zones'), 'America/Bogota', '-05:00'),\n(next_id('1_time_zones'), 'America/Boise', '-06:00'),\n(next_id('1_time_zones'), 'America/Cambridge_Bay', '-06:00'),\n(next_id('1_time_zones'), 'America/Campo_Grande', '-04:00'),\n(next_id('1_time_zones'), 'America/Cancun', '-05:00'),\n(next_id('1_time_zones'), 'America/Caracas', '-04:00'),\n(next_id('1_time_zones'), 'America/Cayenne', '-03:00'),\n(next_id('1_time_zones'), 'America/Cayman', '-05:00'),\n(next_id('1_time_zones'), 'America/Chicago', '-05:00'),\n(next_id('1_time_zones'), 'America/Chihuahua', '-06:00'),\n(next_id('1_time_zones'), 'America/Costa_Rica', '-06:00'),\n(next_id('1_time_zones'), 'America/Creston', '-07:00'),\n(next_id('1_time_zones'), 'America/Cuiaba', '-04:00'),\n(next_id('1_time_zones'), 'America/Curacao', '-04:00'),\n(next_id('1_time_zones'), 'America/Danmarkshavn', 'UTC'),\n(next_id('1_time_zones'), 'America/Dawson', '-07:00'),\n(next_id('1_time_zones'), 'America/Dawson_Creek', '-07:00'),\n(next_id('1_time_zones'), 'America/Denver', '-06:00'),\n(next_id('1_time_zones'), 'America/Detroit', '-04:00'),\n(next_id('1_time_zones'), 'America/Dominica', '-04:00'),\n(next_id('1_time_zones'), 'America/Edmonton', '-06:00'),\n(next_id('1_time_zones'), 'America/Eirunepe', '-05:00'),\n(next_id('1_time_zones'), 'America/El_Salvador', '-06:00'),\n(next_id('1_time_zones'), 'America/Fort_Nelson', '-07:00'),\n(next_id('1_time_zones'), 'America/Fortaleza', '-03:00'),\n(next_id('1_time_zones'), 'America/Glace_Bay', '-03:00'),\n(next_id('1_time_zones'), 'America/Godthab', '-02:00'),\n(next_id('1_time_zones'), 'America/Goose_Bay', '-03:00'),\n(next_id('1_time_zones'), 'America/Grand_Turk', '-04:00'),\n(next_id('1_time_zones'), 'America/Grenada', '-04:00'),\n(next_id('1_time_zones'), 'America/Guadeloupe', '-04:00'),\n(next_id('1_time_zones'), 'America/Guatemala', '-06:00'),\n(next_id('1_time_zones'), 'America/Guayaquil', '-05:00'),\n(next_id('1_time_zones'), 'America/Guyana', '-04:00'),\n(next_id('1_time_zones'), 'America/Halifax', '-03:00'),\n(next_id('1_time_zones'), 'America/Havana', '-04:00'),\n(next_id('1_time_zones'), 'America/Hermosillo', '-07:00'),\n(next_id('1_time_zones'), 'America/Indiana/Indianapolis', '-04:00'),\n(next_id('1_time_zones'), 'America/Indiana/Knox', '-05:00'),\n(next_id('1_time_zones'), 'America/Indiana/Marengo', '-04:00'),\n(next_id('1_time_zones'), 'America/Indiana/Petersburg', '-04:00'),\n(next_id('1_time_zones'), 'America/Indiana/Tell_City', '-05:00'),\n(next_id('1_time_zones'), 'America/Indiana/Vevay', '-04:00'),\n(next_id('1_time_zones'), 'America/Indiana/Vincennes', '-04:00'),\n(next_id('1_time_zones'), 'America/Indiana/Winamac', '-04:00'),\n(next_id('1_time_zones'), 'America/Inuvik', '-06:00'),\n(next_id('1_time_zones'), 'America/Iqaluit', '-04:00'),\n(next_id('1_time_zones'), 'America/Jamaica', '-05:00'),\n(next_id('1_time_zones'), 'America/Juneau', '-08:00'),\n(next_id('1_time_zones'), 'America/Kentucky/Louisville', '-04:00'),\n(next_id('1_time_zones'), 'America/Kentucky/Monticello', '-04:00'),\n(next_id('1_time_zones'), 'America/Kralendijk', '-04:00'),\n(next_id('1_time_zones'), 'America/La_Paz', '-04:00'),\n(next_id('1_time_zones'), 'America/Lima', '-05:00'),\n(next_id('1_time_zones'), 'America/Los_Angeles', '-07:00'),\n(next_id('1_time_zones'), 'America/Lower_Princes', '-04:00'),\n(next_id('1_time_zones'), 'America/Maceio', '-03:00'),\n(next_id('1_time_zones'), 'America/Managua', '-06:00'),\n(next_id('1_time_zones'), 'America/Manaus', '-04:00'),\n(next_id('1_time_zones'), 'America/Marigot', '-04:00'),\n(next_id('1_time_zones'), 'America/Martinique', '-04:00'),\n(next_id('1_time_zones'), 'America/Matamoros', '-05:00'),\n(next_id('1_time_zones'), 'America/Mazatlan', '-06:00'),\n(next_id('1_time_zones'), 'America/Menominee', '-05:00'),\n(next_id('1_time_zones'), 'America/Merida', '-05:00'),\n(next_id('1_time_zones'), 'America/Metlakatla', '-08:00'),\n(next_id('1_time_zones'), 'America/Mexico_City', '-05:00'),\n(next_id('1_time_zones'), 'America/Miquelon', '-02:00'),\n(next_id('1_time_zones'), 'America/Moncton', '-03:00'),\n(next_id('1_time_zones'), 'America/Monterrey', '-05:00'),\n(next_id('1_time_zones'), 'America/Montevideo', '-03:00'),\n(next_id('1_time_zones'), 'America/Montserrat', '-04:00'),\n(next_id('1_time_zones'), 'America/Nassau', '-04:00'),\n(next_id('1_time_zones'), 'America/New_York', '-04:00'),\n(next_id('1_time_zones'), 'America/Nipigon', '-04:00'),\n(next_id('1_time_zones'), 'America/Nome', '-08:00'),\n(next_id('1_time_zones'), 'America/Noronha', '-02:00'),\n(next_id('1_time_zones'), 'America/North_Dakota/Beulah', '-05:00'),\n(next_id('1_time_zones'), 'America/North_Dakota/Center', '-05:00'),\n(next_id('1_time_zones'), 'America/North_Dakota/New_Salem', '-05:00'),\n(next_id('1_time_zones'), 'America/Ojinaga', '-06:00'),\n(next_id('1_time_zones'), 'America/Panama', '-05:00'),\n(next_id('1_time_zones'), 'America/Pangnirtung', '-04:00'),\n(next_id('1_time_zones'), 'America/Paramaribo', '-03:00'),\n(next_id('1_time_zones'), 'America/Phoenix', '-07:00'),\n(next_id('1_time_zones'), 'America/Port-au-Prince', '-04:00'),\n(next_id('1_time_zones'), 'America/Port_of_Spain', '-04:00'),\n(next_id('1_time_zones'), 'America/Porto_Velho', '-04:00'),\n(next_id('1_time_zones'), 'America/Puerto_Rico', '-04:00'),\n(next_id('1_time_zones'), 'America/Punta_Arenas', '-03:00'),\n(next_id('1_time_zones'), 'America/Rainy_River', '-05:00'),\n(next_id('1_time_zones'), 'America/Rankin_Inlet', '-05:00'),\n(next_id('1_time_zones'), 'America/Recife', '-03:00'),\n(next_id('1_time_zones'), 'America/Regina', '-06:00'),\n(next_id('1_time_zones'), 'America/Resolute', '-05:00'),\n(next_id('1_time_zones'), 'America/Rio_Branco', '-05:00'),\n(next_id('1_time_zones'), 'America/Santarem', '-03:00'),\n(next_id('1_time_zones'), 'America/Santiago', '-04:00'),\n(next_id('1_time_zones'), 'America/Santo_Domingo', '-04:00'),\n(next_id('1_time_zones'), 'America/Sao_Paulo', '-03:00'),\n(next_id('1_time_zones'), 'America/Scoresbysund', 'UTC'),\n(next_id('1_time_zones'), 'America/Sitka', '-08:00'),\n(next_id('1_time_zones'), 'America/St_Barthelemy', '-04:00'),\n(next_id('1_time_zones'), 'America/St_Johns', '-02:30'),\n(next_id('1_time_zones'), 'America/St_Kitts', '-04:00'),\n(next_id('1_time_zones'), 'America/St_Lucia', '-04:00'),\n(next_id('1_time_zones'), 'America/St_Thomas', '-04:00'),\n(next_id('1_time_zones'), 'America/St_Vincent', '-04:00'),\n(next_id('1_time_zones'), 'America/Swift_Current', '-06:00'),\n(next_id('1_time_zones'), 'America/Tegucigalpa', '-06:00'),\n(next_id('1_time_zones'), 'America/Thule', '-03:00'),\n(next_id('1_time_zones'), 'America/Thunder_Bay', '-04:00'),\n(next_id('1_time_zones'), 'America/Tijuana', '-07:00'),\n(next_id('1_time_zones'), 'America/Toronto', '-04:00'),\n(next_id('1_time_zones'), 'America/Tortola', '-04:00'),\n(next_id('1_time_zones'), 'America/Vancouver', '-07:00'),\n(next_id('1_time_zones'), 'America/Whitehorse', '-07:00'),\n(next_id('1_time_zones'), 'America/Winnipeg', '-05:00'),\n(next_id('1_time_zones'), 'America/Yakutat', '-08:00'),\n(next_id('1_time_zones'), 'America/Yellowknife', '-06:00'),\n(next_id('1_time_zones'), 'Antarctica/Casey', '+08:00'),\n(next_id('1_time_zones'), 'Antarctica/Davis', '+07:00'),\n(next_id('1_time_zones'), 'Antarctica/DumontDUrville', '+10:00'),\n(next_id('1_time_zones'), 'Antarctica/Macquarie', '+11:00'),\n(next_id('1_time_zones'), 'Antarctica/Mawson', '+05:00'),\n(next_id('1_time_zones'), 'Antarctica/McMurdo', '+12:00'),\n(next_id('1_time_zones'), 'Antarctica/Palmer', '-03:00'),\n(next_id('1_time_zones'), 'Antarctica/Rothera', '-03:00'),\n(next_id('1_time_zones'), 'Antarctica/Syowa', '+03:00'),\n(next_id('1_time_zones'), 'Antarctica/Troll', '+02:00'),\n(next_id('1_time_zones'), 'Antarctica/Vostok', '+06:00'),\n(next_id('1_time_zones'), 'Arctic/Longyearbyen', '+02:00'),\n(next_id('1_time_zones'), 'Asia/Aden', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Almaty', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Amman', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Anadyr', '+12:00'),\n(next_id('1_time_zones'), 'Asia/Aqtau', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Aqtobe', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Ashgabat', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Atyrau', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Baghdad', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Bahrain', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Baku', '+04:00'),\n(next_id('1_time_zones'), 'Asia/Bangkok', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Barnaul', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Beirut', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Bishkek', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Brunei', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Chita', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Choibalsan', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Chongqing', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Colombo', '+05:30'),\n(next_id('1_time_zones'), 'Asia/Damascus', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Dhaka', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Dili', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Dubai', '+04:00'),\n(next_id('1_time_zones'), 'Asia/Dushanbe', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Famagusta', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Gaza', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Hebron', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Ho_Chi_Minh', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Hong_Kong', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Hovd', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Irkutsk', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Jakarta', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Jayapura', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Jerusalem', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Kabul', '+04:30'),\n(next_id('1_time_zones'), 'Asia/Kamchatka', '+12:00'),\n(next_id('1_time_zones'), 'Asia/Karachi', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Kathmandu', '+05:45'),\n(next_id('1_time_zones'), 'Asia/Khandyga', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Kolkata', '+05:30'),\n(next_id('1_time_zones'), 'Asia/Krasnoyarsk', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Kuala_Lumpur', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Kuching', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Kuwait', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Macau', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Magadan', '+11:00'),\n(next_id('1_time_zones'), 'Asia/Makassar', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Manila', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Muscat', '+04:00'),\n(next_id('1_time_zones'), 'Asia/Nicosia', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Novokuznetsk', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Novosibirsk', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Omsk', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Oral', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Phnom_Penh', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Pontianak', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Pyongyang', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Qatar', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Qostanay', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Qyzylorda', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Riyadh', '+03:00'),\n(next_id('1_time_zones'), 'Asia/Sakhalin', '+11:00'),\n(next_id('1_time_zones'), 'Asia/Samarkand', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Seoul', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Shanghai', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Singapore', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Srednekolymsk', '+11:00'),\n(next_id('1_time_zones'), 'Asia/Taipei', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Tashkent', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Tbilisi', '+04:00'),\n(next_id('1_time_zones'), 'Asia/Tehran', '+04:30'),\n(next_id('1_time_zones'), 'Asia/Thimphu', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Tokyo', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Tomsk', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Ulaanbaatar', '+08:00'),\n(next_id('1_time_zones'), 'Asia/Urumqi', '+06:00'),\n(next_id('1_time_zones'), 'Asia/Ust-Nera', '+10:00'),\n(next_id('1_time_zones'), 'Asia/Vientiane', '+07:00'),\n(next_id('1_time_zones'), 'Asia/Vladivostok', '+10:00'),\n(next_id('1_time_zones'), 'Asia/Yakutsk', '+09:00'),\n(next_id('1_time_zones'), 'Asia/Yangon', '+06:30'),\n(next_id('1_time_zones'), 'Asia/Yekaterinburg', '+05:00'),\n(next_id('1_time_zones'), 'Asia/Yerevan', '+04:00'),\n(next_id('1_time_zones'), 'Atlantic/Azores', 'UTC'),\n(next_id('1_time_zones'), 'Atlantic/Bermuda', '-03:00'),\n(next_id('1_time_zones'), 'Atlantic/Canary', '+01:00'),\n(next_id('1_time_zones'), 'Atlantic/Cape_Verde', '-01:00'),\n(next_id('1_time_zones'), 'Atlantic/Faroe', '+01:00'),\n(next_id('1_time_zones'), 'Atlantic/Madeira', '+01:00'),\n(next_id('1_time_zones'), 'Atlantic/Reykjavik', 'UTC'),\n(next_id('1_time_zones'), 'Atlantic/South_Georgia', '-02:00'),\n(next_id('1_time_zones'), 'Atlantic/St_Helena', 'UTC'),\n(next_id('1_time_zones'), 'Atlantic/Stanley', '-03:00'),\n(next_id('1_time_zones'), 'Australia/Adelaide', '+09:30'),\n(next_id('1_time_zones'), 'Australia/Brisbane', '+10:00'),\n(next_id('1_time_zones'), 'Australia/Broken_Hill', '+09:30'),\n(next_id('1_time_zones'), 'Australia/Currie', '+10:00'),\n(next_id('1_time_zones'), 'Australia/Darwin', '+09:30'),\n(next_id('1_time_zones'), 'Australia/Eucla', '+08:45'),\n(next_id('1_time_zones'), 'Australia/Hobart', '+10:00'),\n(next_id('1_time_zones'), 'Australia/Lindeman', '+10:00'),\n(next_id('1_time_zones'), 'Australia/Lord_Howe', '+10:30'),\n(next_id('1_time_zones'), 'Australia/Melbourne', '+10:00'),\n(next_id('1_time_zones'), 'Australia/Perth', '+08:00'),\n(next_id('1_time_zones'), 'Australia/Sydney', '+10:00'),\n(next_id('1_time_zones'), 'Europe/Amsterdam', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Andorra', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Astrakhan', '+04:00'),\n(next_id('1_time_zones'), 'Europe/Athens', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Belgrade', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Berlin', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Bratislava', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Brussels', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Bucharest', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Budapest', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Busingen', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Chisinau', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Copenhagen', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Dublin', '+01:00'),\n(next_id('1_time_zones'), 'Europe/Gibraltar', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Guernsey', '+01:00'),\n(next_id('1_time_zones'), 'Europe/Helsinki', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Isle_of_Man', '+01:00'),\n(next_id('1_time_zones'), 'Europe/Istanbul', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Jersey', '+01:00'),\n(next_id('1_time_zones'), 'Europe/Kaliningrad', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Kiev', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Kirov', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Lisbon', '+01:00'),\n(next_id('1_time_zones'), 'Europe/Ljubljana', '+02:00'),\n(next_id('1_time_zones'), 'Europe/London', '+01:00'),\n(next_id('1_time_zones'), 'Europe/Luxembourg', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Madrid', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Malta', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Mariehamn', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Minsk', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Monaco', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Moscow', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Oslo', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Paris', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Podgorica', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Prague', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Riga', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Rome', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Samara', '+04:00'),\n(next_id('1_time_zones'), 'Europe/San_Marino', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Sarajevo', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Saratov', '+04:00'),\n(next_id('1_time_zones'), 'Europe/Simferopol', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Skopje', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Sofia', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Stockholm', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Tallinn', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Tirane', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Ulyanovsk', '+04:00'),\n(next_id('1_time_zones'), 'Europe/Uzhgorod', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Vaduz', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Vatican', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Vienna', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Vilnius', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Volgograd', '+04:00'),\n(next_id('1_time_zones'), 'Europe/Warsaw', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Zagreb', '+02:00'),\n(next_id('1_time_zones'), 'Europe/Zaporozhye', '+03:00'),\n(next_id('1_time_zones'), 'Europe/Zurich', '+02:00'),\n(next_id('1_time_zones'), 'Indian/Antananarivo', '+03:00'),\n(next_id('1_time_zones'), 'Indian/Chagos', '+06:00'),\n(next_id('1_time_zones'), 'Indian/Christmas', '+07:00'),\n(next_id('1_time_zones'), 'Indian/Cocos', '+06:30'),\n(next_id('1_time_zones'), 'Indian/Comoro', '+03:00'),\n(next_id('1_time_zones'), 'Indian/Kerguelen', '+05:00'),\n(next_id('1_time_zones'), 'Indian/Mahe', '+04:00'),\n(next_id('1_time_zones'), 'Indian/Maldives', '+05:00'),\n(next_id('1_time_zones'), 'Indian/Mauritius', '+04:00'),\n(next_id('1_time_zones'), 'Indian/Mayotte', '+03:00'),\n(next_id('1_time_zones'), 'Indian/Reunion', '+04:00'),\n(next_id('1_time_zones'), 'Pacific/Apia', '+13:00'),\n(next_id('1_time_zones'), 'Pacific/Auckland', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Bougainville', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Chatham', '+12:45'),\n(next_id('1_time_zones'), 'Pacific/Chuuk', '+10:00'),\n(next_id('1_time_zones'), 'Pacific/Easter', '-06:00'),\n(next_id('1_time_zones'), 'Pacific/Efate', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Enderbury', '+13:00'),\n(next_id('1_time_zones'), 'Pacific/Fakaofo', '+13:00'),\n(next_id('1_time_zones'), 'Pacific/Fiji', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Funafuti', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Galapagos', '-06:00'),\n(next_id('1_time_zones'), 'Pacific/Gambier', '-09:00'),\n(next_id('1_time_zones'), 'Pacific/Guadalcanal', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Guam', '+10:00'),\n(next_id('1_time_zones'), 'Pacific/Honolulu', '-10:00'),\n(next_id('1_time_zones'), 'Pacific/Kiritimati', '+14:00'),\n(next_id('1_time_zones'), 'Pacific/Kosrae', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Kwajalein', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Majuro', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Marquesas', '-09:30'),\n(next_id('1_time_zones'), 'Pacific/Midway', '-11:00'),\n(next_id('1_time_zones'), 'Pacific/Nauru', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Niue', '-11:00'),\n(next_id('1_time_zones'), 'Pacific/Norfolk', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Noumea', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Pago_Pago', '-11:00'),\n(next_id('1_time_zones'), 'Pacific/Palau', '+09:00'),\n(next_id('1_time_zones'), 'Pacific/Pitcairn', '-08:00'),\n(next_id('1_time_zones'), 'Pacific/Pohnpei', '+11:00'),\n(next_id('1_time_zones'), 'Pacific/Port_Moresby', '+10:00'),\n(next_id('1_time_zones'), 'Pacific/Rarotonga', '-10:00'),\n(next_id('1_time_zones'), 'Pacific/Saipan', '+10:00'),\n(next_id('1_time_zones'), 'Pacific/Tahiti', '-10:00'),\n(next_id('1_time_zones'), 'Pacific/Tarawa', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Tongatapu', '+13:00'),\n(next_id('1_time_zones'), 'Pacific/Wake', '+12:00'),\n(next_id('1_time_zones'), 'Pacific/Wallis', '+12:00');\n`\n"
  },
  {
    "path": "packages/migration/updates/migration_update_exec.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage updates\n\nvar MigrationUpdatePriceCreateExec = `\nINSERT INTO \"1_platform_parameters\" (id, name, value, conditions) VALUES\n    (next_id('1_platform_parameters'),'price_create_rate', '1000000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_ecosystem', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_table', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_column', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_contract', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_menu', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_page', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_snippet', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_view', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_application', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_token', '5000', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_lang', '1', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'),'price_create_exec_@1_new_section', '1', 'ContractAccess(\"@1UpdatePlatformParam\")');\n`\n\nvar MigrationUpdatePriceExec = `\nINSERT INTO \"1_platform_parameters\" (id, name, value, conditions) VALUES\n\t(next_id('1_platform_parameters'), 'price_exec_get_block', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_int', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_map_keys', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_pub_to_hex', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_sqrt', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_json_encode_indent', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_encode_base64', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_sorted_keys', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_hex_to_pub', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_throw', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_create_contract', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_edit_language', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_date_time', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_edit_ecosys_name', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_update_notifications', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_update_roles_notifications', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_contract_name', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_bnd_wallet', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_check_signature', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_row_conditions', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_append', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_round', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_lang_res', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_to_upper', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_allow_change_condition', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_bytes_to_string', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_app_param', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_float', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_money', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_del_table', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_string_to_bytes', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_date_time_location', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_h_mac', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_hex_to_bytes', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_split', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_column_type', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_unix_date_time_location', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_contract_conditions', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_random', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_type', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_del_column', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_update_nodes_ban', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_log10', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_validate_edit_contract_new_value', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_format_money', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_create_language', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_role_access', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_decode_base64', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_unix_date_time', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_history', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_floor', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_json_decode', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_update_contract', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_log', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_json_encode', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_to_lower', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_unbnd_wallet', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_history_row', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_block_time', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_contract_access', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_transaction_info', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_pow', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_hash', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_check_condition', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_str', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_trim_space', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_address_to_id', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_id_to_address', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_pub_to_id', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_ecosys_param', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_sys_param_string', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_sys_param_int', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_sys_fuel', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_validate_condition', '30', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_eval_condition', '20', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_has_prefix', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_contains', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_replace', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_join', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_update_lang', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_size', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_substr', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_contracts_list', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_is_object', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_compile_contract', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_flush_contract', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_eval', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_len', '5', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_bind_wallet', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_unbind_wallet', '10', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_create_ecosystem', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_table_conditions', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_create_table', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_perm_table', '100', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_column_condition', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_create_column', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_perm_column', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_contract_by_name', '20', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_get_contract_by_id', '20', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_money_div', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_check_sign', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_date_format', '50', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_is_honor_node_key', '10', 'ContractAccess(\"@1UpdatePlatformParam\")');\n`\n\nvar MigrationUpdateAccessExec = `\nINSERT INTO \"1_platform_parameters\" (id, name, value, conditions) VALUES\n\t(next_id('1_platform_parameters'), 'access_exec_compile_contract', 'ContractAccess(\"@1NewContract\", \"@1EditContract\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_update_contract', 'ContractAccess(\"@1EditContract\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_create_contract', 'ContractAccess(\"@1NewContract\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_create_table', 'ContractAccess(\"@1NewTable\", \"@1NewTableJoint\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_flush_contract', 'ContractAccess(\"@1NewContract\", \"@1EditContract\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_perm_table', 'ContractAccess(\"@1EditTable\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_table_conditions', 'ContractAccess(\"@1NewTable\", \"@1Import\", \"@1NewTableJoint\", \"@1EditTable\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_column_condition', 'ContractAccess(\"@1NewColumn\", \"@1EditColumn\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_create_column', 'ContractAccess(\"@1NewColumn\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_perm_column', 'ContractAccess(\"@1EditColumn\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_create_language', 'ContractAccess(\"@1NewLang\", \"@1NewLangJoint\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_edit_language', 'ContractAccess(\"@1EditLang\", \"@1EditLangJoint\", \"@1Import\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_create_ecosystem', 'ContractAccess(\"@1NewEcosystem\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_edit_ecosys_name', 'ContractAccess(\"@1EditEcosystemName\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_bind_wallet', 'ContractAccess(\"@1BindWallet\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_unbind_wallet', 'ContractAccess(\"@1UnbindWallet\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_set_contract_wallet', 'ContractAccess(\"@1BindWallet\", \"@1UnbindWallet\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'access_exec_update_nodes_ban', 'ContractAccess(\"@1CheckNodesBan\")', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n    (next_id('1_platform_parameters'), 'access_exec_create_view', 'ContractAccess(\"@1NewView\")', 'ContractAccess(\"@1UpdatePlatformParam\")');\n`\n\nvar tentative = `\nINSERT INTO \"1_platform_parameters\" (id, name, value, conditions) VALUES\n\t(next_id('1_platform_parameters'), 'block_reward','10','ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'external_blockchain', '', 'ContractAccess(\"@1UpdatePlatformParam\")'),\n\t(next_id('1_platform_parameters'), 'price_exec_send_external_transaction', '50', 'ContractAccess(\"@1UpdatePlatformParam\")');\n`\n"
  },
  {
    "path": "packages/modes/api.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage modes\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/service/jsonrpc\"\n\t\"net/http\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/api\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n)\n\nfunc RegisterRoutes() http.Handler {\n\tm := api.Mode{\n\t\tEcosystemGetter:   GetEcosystemGetter(),\n\t\tContractRunner:    GetSmartContractRunner(),\n\t\tClientTxProcessor: GetClientTxPreprocessor(),\n\t}\n\n\tr := api.NewRouter(m)\n\tif !conf.Config.IsSupportingCLB() {\n\t\tm.SetBlockchainRoutes(r)\n\t}\n\n\tif conf.Config.IsSubNode() {\n\t\tm.SetSubNodeRoutes(r)\n\t}\n\n\tif conf.Config.IsSupportingCLB() {\n\t}\n\n\treturn r.GetAPI()\n}\n\ntype JsonRpcRoutes struct {\n\ts    *rpcServer\n\tnext http.Handler\n}\n\nfunc (s *JsonRpcRoutes) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tif r.RequestURI == \"/\" {\n\t\ts.s.ServeHTTP(w, r)\n\t\treturn\n\t}\n\ts.next.ServeHTTP(w, r)\n}\n\nfunc RegisterJsonRPCRoutes(next http.Handler) http.Handler {\n\tm := jsonrpc.Mode{\n\t\tEcosystemGetter:   GetEcosystemGetter(),\n\t\tContractRunner:    GetSmartContractRunner(),\n\t\tClientTxProcessor: GetClientTxPreprocessor(),\n\t}\n\n\trpc := newRpcServer(m)\n\trpc.lo.Lock()\n\tdefer rpc.lo.Unlock()\n\terr := rpc.enableRpc(conf.Config.JsonRPC.Namespace)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &JsonRpcRoutes{rpc, next}\n}\n"
  },
  {
    "path": "packages/modes/client_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage modes\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar ErrDiffKey = errors.New(\"Different keys\")\n\ntype blockchainTxPreprocessor struct{}\n\nfunc (p blockchainTxPreprocessor) ProcessClientTxBatches(txDatas [][]byte, key int64, le *log.Entry) (retTx []string, err error) {\n\tvar rtxs []*sqldb.RawTx\n\tfor _, txData := range txDatas {\n\t\trtx := &transaction.Transaction{}\n\t\tif err = rtx.Unmarshall(bytes.NewBuffer(txData), true); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trtxs = append(rtxs, rtx.SetRawTx())\n\t\tretTx = append(retTx, fmt.Sprintf(\"%x\", rtx.Hash()))\n\t}\n\terr = sqldb.SendTxBatches(rtxs)\n\treturn\n}\n\ntype ClbTxPreprocessor struct{}\n\n/*\nfunc (p ClbTxPreprocessor) ProcessClientTranstaction(txData []byte, key int64, le *log.Entry) (string, error) {\n\n\ttx, err := transaction.UnmarshallTransaction(bytes.NewBuffer(txData), true)\n\tif err != nil {\n\t\tle.WithFields(log.Fields{\"type\": consts.ParseError, \"error\": err}).Error(\"on unmarshaling user tx\")\n\t\treturn \"\", err\n\t}\n\n\tts := &sqldb.TransactionStatus{\n\t\tBlockId:  1,\n\t\tHash:     tx.TxHash,\n\t\tTimestamp:     time.Now().Unix(),\n\t\tWalletID: key,\n\t\tType:     tx.Rtx.Type(),\n\t}\n\n\tif err := ts.Create(); err != nil {\n\t\tle.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on creating tx status\")\n\t\treturn \"\", err\n\t}\n\n\tres, _, err := tx.CallCLBContract()\n\tif err != nil {\n\t\tle.WithFields(log.Fields{\"type\": consts.ParseError, \"error\": err}).Error(\"on execution contract\")\n\t\treturn \"\", err\n\t}\n\n\tif err := sqldb.SetTransactionStatusBlockMsg(nil, 1, res, tx.TxHash); err != nil {\n\t\tle.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"tx_hash\": tx.TxHash}).Error(\"updating transaction status block id\")\n\t\treturn \"\", err\n\t}\n\n\treturn string(converter.BinToHex(tx.TxHash)), nil\n}*/\n\nfunc (p ClbTxPreprocessor) ProcessClientTxBatches(txData [][]byte, key int64, le *log.Entry) ([]string, error) {\n\treturn nil, nil\n}\n\nfunc GetClientTxPreprocessor() types.ClientTxPreprocessor {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn ClbTxPreprocessor{}\n\t}\n\n\treturn blockchainTxPreprocessor{}\n}\n\n// BlockchainSCRunner implementls SmartContractRunner for blockchain mode\ntype BlockchainSCRunner struct{}\n\n// RunContract runs smart contract on blockchain mode\nfunc (runner BlockchainSCRunner) RunContract(data, hash []byte, keyID, tnow int64, le *log.Entry) error {\n\tif err := transaction.CreateTransaction(data, hash, keyID, tnow); err != nil {\n\t\tle.WithFields(log.Fields{\"type\": consts.ContractError, \"error\": err}).Error(\"Executing contract\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// CLBSCRunner implementls SmartContractRunner for clb mode\ntype CLBSCRunner struct{}\n\n// RunContract runs smart contract on clb mode\nfunc (runner CLBSCRunner) RunContract(data, hash []byte, keyID, tnow int64, le *log.Entry) error {\n\tproc := GetClientTxPreprocessor()\n\t_, err := proc.ProcessClientTxBatches([][]byte{data}, keyID, le)\n\tif err != nil {\n\t\tle.WithFields(log.Fields{\"error\": consts.ContractError}).Error(\"on run internal NewUser\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// GetSmartContractRunner returns mode boundede implementation of SmartContractRunner\nfunc GetSmartContractRunner() types.SmartContractRunner {\n\tif !conf.Config.IsSupportingCLB() {\n\t\treturn BlockchainSCRunner{}\n\t}\n\n\treturn CLBSCRunner{}\n}\n"
  },
  {
    "path": "packages/modes/daemons.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage modes\n"
  },
  {
    "path": "packages/modes/ecosystem_getter.go",
    "content": "package modes\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/api\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc GetEcosystemGetter() types.EcosystemGetter {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn CLBEcosystemGetter{}\n\t}\n\n\treturn BCEcosystemGetter{}\n}\n\ntype BCEcosystemGetter struct {\n\tlogger *log.Entry\n}\n\nfunc (ng BCEcosystemGetter) GetEcosystemName(id int64) (string, error) {\n\tecosystem := &sqldb.Ecosystem{}\n\tfound, err := ecosystem.Get(nil, id)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting ecosystem from db\")\n\t\treturn \"\", err\n\t}\n\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound, \"id\": id, \"error\": api.ErrEcosystemNotFound}).Error(\"ecosystem not found\")\n\t\treturn \"\", err\n\t}\n\n\treturn ecosystem.Name, nil\n}\n\nfunc (g BCEcosystemGetter) GetEcosystemLookup() ([]int64, []string, error) {\n\treturn sqldb.GetAllSystemStatesIDs()\n}\n\nfunc (v BCEcosystemGetter) ValidateId(formEcosysID, clientEcosysID int64, le *log.Entry) (int64, error) {\n\tif formEcosysID <= 0 {\n\t\treturn clientEcosysID, nil\n\t}\n\n\tcount, err := sqldb.NewDbTransaction(nil).GetNextID(\"1_ecosystems\")\n\tif err != nil {\n\t\tle.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting next id of ecosystems\")\n\t\treturn 0, err\n\t}\n\n\tif formEcosysID >= count {\n\t\tle.WithFields(log.Fields{\"state_id\": formEcosysID, \"count\": count, \"type\": consts.ParameterExceeded}).Error(\"ecosystem is larger then max count\")\n\t\treturn 0, api.ErrEcosystemNotFound\n\t}\n\n\treturn formEcosysID, nil\n}\n\ntype CLBEcosystemGetter struct{}\n\nfunc (g CLBEcosystemGetter) GetEcosystemLookup() ([]int64, []string, error) {\n\treturn []int64{1}, []string{\"Platform ecosystem\"}, nil\n}\n\nfunc (CLBEcosystemGetter) ValidateId(id, clientID int64, le *log.Entry) (int64, error) {\n\treturn consts.DefaultCLB, nil\n}\n\nfunc (ng CLBEcosystemGetter) GetEcosystemName(id int64) (string, error) {\n\treturn \"Platform ecosystem\", nil\n}\n"
  },
  {
    "path": "packages/modes/mode_fabrics.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage modes\n\nimport (\n\t\"context\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/clbmanager\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/daemons\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpserver\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc GetDaemonLoader() types.DaemonFactory {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn CLBDaemonFactory{\n\t\t\tlogger: log.WithFields(log.Fields{\"loader\": \"clb_daemon_loader\"}),\n\t\t}\n\t}\n\n\tif conf.Config.IsSubNode() {\n\t\treturn SNDaemonFactory{\n\t\t\tlogger: log.WithFields(log.Fields{\"loader\": \"subnode_daemon_loader\"}),\n\t\t}\n\t}\n\n\treturn BCDaemonFactory{\n\t\tlogger: log.WithFields(log.Fields{\"loader\": \"blockchain_daemon_loader\"}),\n\t}\n}\n\n// BCDaemonFactory allow load blockchain daemons\ntype BCDaemonFactory struct {\n\tlogger *log.Entry\n}\n\n// Load loads blockchain daemons\nfunc (l BCDaemonFactory) Load(ctx context.Context) error {\n\tif err := daemons.InitialLoad(l.logger); err != nil {\n\t\treturn err\n\t}\n\n\tif err := syspar.SysUpdate(nil); err != nil {\n\t\tlog.Errorf(\"can't read platform parameters: %s\", utils.ErrInfo(err))\n\t\treturn err\n\t}\n\tif err := syspar.SysTableColType(nil); err != nil {\n\t\tlog.Errorf(\"can't table col type: %s\", utils.ErrInfo(err))\n\t\treturn err\n\t}\n\n\tif data, ok := block.GetDataFromFirstBlock(); ok {\n\t\tsyspar.SetFirstBlockData(data)\n\t}\n\n\tmode := \"Public blockchain\"\n\tif syspar.IsPrivateBlockchain() {\n\t\tmode = \"Private Blockchain\"\n\t}\n\n\tlogMode(l.logger, mode)\n\n\tl.logger.Info(\"load contracts\")\n\tif err := smart.LoadContracts(); err != nil {\n\t\tlog.Errorf(\"Load Contracts error: %s\", err)\n\t\treturn err\n\t}\n\n\tl.logger.Info(\"start daemons\")\n\tdaemons.StartDaemons(ctx, l.GetDaemonsList())\n\n\tif err := tcpserver.TcpListener(conf.Config.TCPServer.Str()); err != nil {\n\t\tlog.Errorf(\"can't start tcp servers, stop\")\n\t\treturn err\n\t}\n\n\tna := node.NewNodeRelevanceService()\n\tna.Run(ctx)\n\n\tif err := node.InitNodesBanService(); err != nil {\n\t\tl.logger.WithError(err).Error(\"Can't init ban service\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (BCDaemonFactory) GetDaemonsList() []string {\n\treturn []string{\n\t\t\"BlocksCollection\",\n\t\t\"BlockGenerator\",\n\t\t\"QueueParserTx\",\n\t\t\"QueueParserBlocks\",\n\t\t\"Disseminator\",\n\t\t\"Confirmations\",\n\t\t\"Scheduler\",\n\t\t\"CandidateNodeVoting\",\n\t\t//\"ExternalNetwork\",\n\t}\n}\n\n// SNDaemonFactory allows load subnode daemons\ntype SNDaemonFactory struct {\n\tlogger *log.Entry\n}\n\n// Load loads subnode daemons\nfunc (l SNDaemonFactory) Load(ctx context.Context) error {\n\tdaemons.InitialLoad(l.logger)\n\n\tif err := syspar.SysUpdate(nil); err != nil {\n\t\tlog.Errorf(\"can't read platform parameters: %s\", utils.ErrInfo(err))\n\t\treturn err\n\t}\n\tif err := syspar.SysTableColType(nil); err != nil {\n\t\tlog.Errorf(\"can't table col type: %s\", utils.ErrInfo(err))\n\t\treturn err\n\t}\n\tif data, ok := block.GetDataFromFirstBlock(); ok {\n\t\tsyspar.SetFirstBlockData(data)\n\t}\n\n\tmode := \"Public blockchain\"\n\tif syspar.IsPrivateBlockchain() {\n\t\tmode = \"Private Blockchain\"\n\t}\n\n\tlogMode(l.logger, mode)\n\n\tl.logger.Info(\"load contracts\")\n\tif err := smart.LoadContracts(); err != nil {\n\t\tlog.Errorf(\"Load Contracts error: %s\", err)\n\t\treturn err\n\t}\n\n\tl.logger.Info(\"start subnode daemons\")\n\tdaemons.StartDaemons(ctx, l.GetDaemonsList())\n\n\tif err := tcpserver.TcpListener(conf.Config.TCPServer.Str()); err != nil {\n\t\tlog.Errorf(\"can't start tcp servers, stop\")\n\t\treturn err\n\t}\n\tnode.NewNodeRelevanceService().Run(ctx)\n\n\tif err := node.InitNodesBanService(); err != nil {\n\t\tl.logger.WithError(err).Error(\"Can't init ban service\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (SNDaemonFactory) GetDaemonsList() []string {\n\treturn []string{\n\t\t\"Scheduler\",\n\t}\n}\n\n// CLBDaemonFactory allows load clb daemons\ntype CLBDaemonFactory struct {\n\tlogger *log.Entry\n}\n\n// Load loads clb daemons\nfunc (l CLBDaemonFactory) Load(ctx context.Context) error {\n\tif err := syspar.SysUpdate(nil); err != nil {\n\t\tl.logger.Errorf(\"can't read platform parameters: %s\", utils.ErrInfo(err))\n\t\treturn err\n\t}\n\tif err := syspar.SysTableColType(nil); err != nil {\n\t\tlog.Errorf(\"can't table col type: %s\", utils.ErrInfo(err))\n\t\treturn err\n\t}\n\tlogMode(l.logger, conf.Config.LocalConf.RunNodeMode)\n\tl.logger.Info(\"load contracts\")\n\tif err := smart.LoadContracts(); err != nil {\n\t\tl.logger.Errorf(\"Load Contracts error: %s\", err)\n\t\treturn err\n\t}\n\n\tl.logger.Info(\"start daemons\")\n\tdaemons.StartDaemons(ctx, l.GetDaemonsList())\n\n\t//\n\tif err := tcpserver.TcpListener(conf.Config.TCPServer.Str()); err != nil {\n\t\tlog.Errorf(\"can't start tcp servers, stop\")\n\t\treturn err\n\t}\n\tclbmanager.InitCLBManager()\n\treturn nil\n}\n\nfunc (CLBDaemonFactory) GetDaemonsList() []string {\n\treturn []string{\n\t\t\"Scheduler\",\n\t}\n}\n\nfunc logMode(logger *log.Entry, mode string) {\n\tlogLevel := log.GetLevel()\n\tlog.SetLevel(log.InfoLevel)\n\tlogger.WithFields(log.Fields{\"mode\": mode}).Info(\"Node running mode\")\n\tlog.SetLevel(logLevel)\n}\n"
  },
  {
    "path": "packages/modes/rpc.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage modes\n\nimport (\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/jsonrpc\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nconst stopTimeout = 5 * time.Second\n\ntype rpcServer struct {\n\tlo          sync.Mutex\n\thttpHandler atomic.Value\n\tmode        jsonrpc.Mode\n}\n\ntype rpcHandler struct {\n\thttp.Handler\n\tserver *jsonrpc.Server\n}\n\ntype adminAPI struct {\n\tsvr *serverApi\n}\n\nfunc (a *adminAPI) GetApis() []any {\n\tvar apis []any\n\tif a == nil {\n\t\treturn nil\n\t}\n\tif a.svr != nil {\n\t\tapis = append(apis, a.svr)\n\t}\n\n\treturn apis\n}\n\nfunc newAdminApi(r *rpcServer) *adminAPI {\n\treturn &adminAPI{\n\t\tsvr: newServerApi(r),\n\t}\n}\n\ntype serverApi struct {\n\trs *rpcServer\n}\n\nfunc newServerApi(r *rpcServer) *serverApi {\n\treturn &serverApi{r}\n}\n\nfunc (s *serverApi) StartJsonRpc(ctx jsonrpc.RequestContext, namespace *string) (bool, *jsonrpc.Error) {\n\tif namespace != nil {\n\t\tconf.Config.JsonRPC.Namespace = *namespace\n\t}\n\ts.rs.httpHandler.Store((*rpcHandler)(nil))\n\terr := s.rs.enableRpc(conf.Config.JsonRPC.Namespace)\n\tif err != nil {\n\t\treturn false, jsonrpc.DefaultError(\"enable rpc failed\")\n\t}\n\n\treturn true, nil\n}\n\nfunc (s *serverApi) StopJsonRpc() (bool, *jsonrpc.Error) {\n\ts.rs.lo.Lock()\n\tdefer s.rs.lo.Unlock()\n\ts.rs.disableRPC()\n\treturn true, nil\n}\n\nfunc (r *rpcServer) rpcIsEnable() bool {\n\treturn r.httpHandler.Load().(*rpcHandler) != nil\n}\n\nfunc (r *rpcServer) getApis(namespace string) []any {\n\tvar apis []any\n\tswitch namespace {\n\tcase jsonrpc.GetNamespace(jsonrpc.NamespaceAdmin):\n\t\tadminApi := newAdminApi(r)\n\t\tapis = append(apis, adminApi.GetApis()...)\n\tcase jsonrpc.GetNamespace(jsonrpc.NamespaceIBAX):\n\t\tibaxApi := jsonrpc.NewIbaxApi(r.mode)\n\t\tapis = append(apis, ibaxApi.GetApis()...)\n\tcase jsonrpc.GetNamespace(jsonrpc.NamespaceNet):\n\t\tnetApi := jsonrpc.NewNetApi()\n\t\tapis = append(apis, netApi.GetApis()...)\n\tcase jsonrpc.GetNamespace(jsonrpc.NamespaceDebug):\n\t\tdebugApi := jsonrpc.NewDebugApi()\n\t\tapis = append(apis, debugApi.GetApis()...)\n\t}\n\treturn apis\n}\n\nfunc (r *rpcServer) enableRpc(namespaces string) error {\n\tif r.rpcIsEnable() {\n\t\treturn fmt.Errorf(\"RPC Server is already enabled\")\n\t}\n\n\tsrv := jsonrpc.NewServer(r.mode)\n\tfor _, m := range strings.Split(namespaces, \",\") {\n\t\tname := strings.TrimSpace(m)\n\t\tfuncs := r.getApis(name)\n\t\tfor _, f := range funcs {\n\t\t\terr := srv.RegisterName(name, f)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tr.httpHandler.Store(&rpcHandler{\n\t\tHandler: jsonrpc.NewMiddlewares(srv, r.mode),\n\t\tserver:  srv,\n\t})\n\treturn nil\n}\n\nfunc (s *rpcServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\thandler := s.httpHandler.Load().(*rpcHandler)\n\tif handler != nil {\n\t\thandler.ServeHTTP(w, r)\n\t\treturn\n\t}\n\n\tw.WriteHeader(http.StatusNotFound)\n}\n\nfunc newRpcServer(m jsonrpc.Mode) *rpcServer {\n\ts := &rpcServer{\n\t\tmode: m,\n\t}\n\ts.httpHandler.Store((*rpcHandler)(nil))\n\treturn s\n}\n\nfunc (r *rpcServer) disableRPC() {\n\thandler := r.httpHandler.Load().(*rpcHandler)\n\tif handler != nil {\n\t\tr.httpHandler.Store((*rpcHandler)(nil))\n\t\thandler.server.Stop()\n\t}\n}\n"
  },
  {
    "path": "packages/network/httpserver/max_body.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage httpserver\n\nimport \"net/http\"\n\ntype MaxBodyReader struct {\n\th http.Handler\n\tn int64\n}\n\nfunc (h *MaxBodyReader) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tr.Body = http.MaxBytesReader(w, r.Body, h.n)\n\th.h.ServeHTTP(w, r)\n}\n\nfunc NewMaxBodyReader(h http.Handler, n int64) http.Handler {\n\treturn &MaxBodyReader{h, n}\n}\n"
  },
  {
    "path": "packages/network/machineState.go",
    "content": "package network\n\nimport \"fmt\"\n\ntype VoteMsg struct {\n\tCurrentBlockHeight int64  `json:\"currentBlockHeight\"`\n\tLocalAddress       string `json:\"localAddress\"`\n\tTcpAddress         string `json:\"tcpAddress\"`\n\tEcosystemID        int64  `json:\"ecosystemID\"`\n\tHash               []byte `json:\"hash\"`\n\tAgree              bool   `json:\"agree\"`\n\tMsg                string `json:\"msg\"`\n\tTime               int64  `json:\"time\"`\n\tSign               []byte `json:\"sign\"`\n}\n\nfunc (voteMsg *VoteMsg) VoteForSign() string {\n\treturn fmt.Sprintf(\"%v,%v,%v,%v,%x,%v\", voteMsg.LocalAddress, voteMsg.TcpAddress, voteMsg.CurrentBlockHeight, voteMsg.EcosystemID, voteMsg.Hash, voteMsg.Time)\n}\n\nfunc (voteMsg *VoteMsg) VerifyVoteForSign() string {\n\treturn fmt.Sprintf(\"%v,%v,%v,%v,%v,%v,%x,%v\", voteMsg.LocalAddress, voteMsg.TcpAddress, voteMsg.CurrentBlockHeight, voteMsg.EcosystemID, voteMsg.Agree, voteMsg.Msg, voteMsg.Hash, voteMsg.Time)\n}\n"
  },
  {
    "path": "packages/network/protocol.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage network\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype ReqTypesFlag uint16\n\n// Types of requests\nconst (\n\tRequestTypeHonorNode ReqTypesFlag = iota + 1\n\tRequestTypeNotHonorNode\n\tRequestTypeStopNetwork\n\tRequestTypeConfirmation\n\tRequestTypeBlockCollection\n\tRequestTypeMaxBlock\n\tRequestTypeVoting\n\tRequestSyncMatchineState\n\n\t// BlocksPerRequest contains count of blocks per request\n\tBlocksPerRequest int = 10\n)\n\nvar ErrNotAccepted = errors.New(\"Not accepted\")\nvar ErrMaxSize = errors.New(\"Size greater than max size\")\n\n// SelfReaderWriter read from Reader to himself and write to io.Writer from himself\ntype SelfReaderWriter interface {\n\tRead(io.Reader) error\n\tWrite(io.Writer) error\n}\n\n// RequestType is type of request\ntype RequestType struct {\n\tType ReqTypesFlag\n}\n\n// Read read first 2 bytes to uint16\nfunc (rt *RequestType) Read(r io.Reader) error {\n\treturn binary.Read(r, binary.LittleEndian, &rt.Type)\n}\n\nfunc (rt *RequestType) Write(w io.Writer) error {\n\treturn binary.Write(w, binary.LittleEndian, rt.Type)\n}\n\n// MaxBlockResponse is max block response\ntype MaxBlockResponse struct {\n\tBlockID int64\n}\n\nfunc (resp *MaxBlockResponse) Read(r io.Reader) error {\n\treturn binary.Read(r, binary.LittleEndian, &resp.BlockID)\n}\n\nfunc (resp *MaxBlockResponse) Write(w io.Writer) error {\n\treturn binary.Write(w, binary.LittleEndian, resp.BlockID)\n}\n\n// GetBodiesRequest contains BlockID\ntype GetBodiesRequest struct {\n\tBlockID      uint32\n\tReverseOrder bool\n}\n\nfunc (req *GetBodiesRequest) Read(r io.Reader) error {\n\tif err := binary.Read(r, binary.LittleEndian, &req.BlockID); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading getBodiesRequest blockID\")\n\t\treturn err\n\t}\n\n\torder, err := readBool(r)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading GetBodiesRequest reverse order\")\n\t}\n\n\treq.ReverseOrder = order\n\treturn nil\n}\n\nfunc (req *GetBodiesRequest) Write(w io.Writer) error {\n\n\tif err := binary.Write(w, binary.LittleEndian, req.BlockID); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on sending GetBodiesRequest blockID\")\n\t\treturn err\n\t}\n\n\tif err := writeBool(w, req.ReverseOrder); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on sending GetBodiesRequest reverse order\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// GetBodyResponse is Data []bytes\ntype GetBodyResponse struct {\n\tData []byte\n}\n\nfunc (resp *GetBodyResponse) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading GetBodyResponse\")\n\t\treturn err\n\t}\n\n\tresp.Data = slice\n\treturn nil\n}\n\nfunc (resp *GetBodyResponse) Write(w io.Writer) error {\n\treturn writeSlice(w, resp.Data)\n}\n\n// ConfirmRequest contains request data\ntype ConfirmRequest struct {\n\tBlockID uint32\n}\n\nfunc (req *ConfirmRequest) Read(r io.Reader) error {\n\treturn binary.Read(r, binary.LittleEndian, &req.BlockID)\n}\n\nfunc (req *ConfirmRequest) Write(w io.Writer) error {\n\treturn binary.Write(w, binary.LittleEndian, req.BlockID)\n}\n\n// ConfirmResponse contains response data\ntype ConfirmResponse struct {\n\t// ConfType uint8\n\tHash []byte `size:\"32\"`\n}\n\nfunc (resp *ConfirmResponse) Read(r io.Reader) error {\n\th, err := readSliceWithSize(r, consts.HashSize)\n\tif err == io.EOF {\n\t} else if err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading ConfirmResponse reverse order\")\n\t\treturn err\n\t}\n\tresp.Hash = h\n\treturn nil\n}\n\nfunc (resp *ConfirmResponse) Write(w io.Writer) error {\n\tif err := writeSliceWithSize(w, resp.Hash, consts.HashSize); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on sending ConfiremResponse hash\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// DisRequest contains request data\ntype DisRequest struct {\n\tData []byte\n}\n\nfunc (req *DisRequest) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading disseminator request\")\n\t\treturn err\n\t}\n\n\treq.Data = slice\n\treturn nil\n}\n\nfunc (req *DisRequest) Write(w io.Writer) error {\n\terr := writeSlice(w, req.Data)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on sending disseminator request\")\n\t}\n\n\treturn err\n}\n\n// DisHashResponse contains response data\ntype DisHashResponse struct {\n\tData []byte\n}\n\nfunc (resp *DisHashResponse) Read(r io.Reader) error {\n\tslice, err := ReadSliceWithMaxSize(r, uint64(syspar.GetMaxTxSize()))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp.Data = slice\n\treturn nil\n}\n\nfunc (resp *DisHashResponse) Write(w io.Writer) error {\n\treturn writeSlice(w, resp.Data)\n}\n\ntype StopNetworkRequest struct {\n\tData []byte\n}\n\nfunc (req *StopNetworkRequest) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq.Data = slice\n\treturn nil\n}\n\nfunc (req *StopNetworkRequest) Write(w io.Writer) error {\n\treturn writeSlice(w, req.Data)\n}\n\ntype StopNetworkResponse struct {\n\tHash []byte\n}\n\nfunc (resp *StopNetworkResponse) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp.Hash = slice\n\treturn nil\n}\n\nfunc (resp *StopNetworkResponse) Write(w io.Writer) error {\n\treturn writeSlice(w, resp.Hash)\n}\n\nfunc readBool(r io.Reader) (bool, error) {\n\tvar val uint8\n\tif err := binary.Read(r, binary.LittleEndian, &val); err != nil {\n\t\treturn false, err\n\t}\n\n\treturn val > 0, nil\n}\n\nfunc writeBool(w io.Writer, val bool) error {\n\tvar intVal int8\n\tif val {\n\t\tintVal = 1\n\t}\n\n\treturn binary.Write(w, binary.LittleEndian, intVal)\n}\n\nfunc ReadSlice(r io.Reader) ([]byte, error) {\n\tsizeBuf := make([]byte, 4)\n\tif _, err := io.ReadFull(r, sizeBuf); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading bytes slice size\")\n\t\treturn nil, err\n\t}\n\n\tsize, errInt := binary.Uvarint(sizeBuf)\n\tif errInt <= 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"errInt\": errInt}).Error(\"on convert sizeBuf to value\")\n\t\treturn nil, fmt.Errorf(\"wrong sizebuf\")\n\t}\n\n\tdata := make([]byte, size)\n\tif _, err := io.ReadFull(r, data); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading block body\")\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\nfunc ReadSliceWithMaxSize(r io.Reader, maxSize uint64) ([]byte, error) {\n\tsizeBuf := make([]byte, 4)\n\tif _, err := io.ReadFull(r, sizeBuf); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading bytes slice size\")\n\t\treturn nil, err\n\t}\n\n\tsize, errInt := binary.Uvarint(sizeBuf)\n\tif errInt <= 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"errInt\": errInt}).Error(\"on convert sizeBuf to value\")\n\t\treturn nil, fmt.Errorf(\"wrong sizebuf\")\n\t}\n\n\tif size > maxSize {\n\t\treturn nil, ErrMaxSize\n\t}\n\n\tdata := make([]byte, size)\n\tif _, err := io.ReadFull(r, data); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading block body\")\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\nfunc readSliceToBuf(r io.Reader, buf []byte) ([]byte, error) {\n\tsizeBuf := make([]byte, 4)\n\tif _, err := io.ReadFull(r, sizeBuf); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading bytes slice size\")\n\t\treturn nil, err\n\t}\n\n\tsize, errInt := binary.Uvarint(sizeBuf)\n\tif errInt <= 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"errInt\": errInt}).Error(\"on convirt sizeBuf to value\")\n\t\treturn nil, fmt.Errorf(\"wrong sizebuf\")\n\t}\n\n\tif cap(buf) < int(size) {\n\t\tbuf = make([]byte, size)\n\t}\n\n\t_, err := io.ReadFull(r, buf[:size])\n\treturn buf, err\n}\n\nfunc writeSlice(w io.Writer, slice []byte) error {\n\tbyteSize := make([]byte, 4)\n\tbinary.PutUvarint(byteSize, uint64(len(slice)))\n\n\tw.Write(byteSize)\n\t_, err := w.Write(slice)\n\treturn err\n}\n\n// if bytesLen < 0 then slice length reads before reading slice body\nfunc readSliceWithSize(r io.Reader, size int) ([]byte, error) {\n\tvar value int32\n\tslice := make([]byte, size)\n\tif err := binary.Read(r, binary.LittleEndian, &value); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading integer from network\")\n\t\treturn slice, err\n\t}\n\t_, err := io.ReadFull(r, slice)\n\treturn slice, err\n}\n\nfunc writeSliceWithSize(w io.Writer, value []byte, size int32) error {\n\tif err := binary.Write(w, binary.LittleEndian, size); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on writing size\")\n\t\treturn err\n\t}\n\n\t_, err := w.Write(value)\n\treturn err\n}\nfunc SendRequestType(reqType int64, w io.Writer) error {\n\t_, err := w.Write(converter.DecToBin(reqType, 2))\n\treturn err\n}\n\nfunc ReadInt(r io.Reader) (int64, error) {\n\tvar value int64\n\terr := binary.Read(r, binary.LittleEndian, &value)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading integer from network\")\n\t\treturn 0, err\n\t}\n\n\treturn value, nil\n}\n\nfunc WriteInt(value int64, w io.Writer) error {\n\tif err := binary.Write(w, binary.LittleEndian, value); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on sending integer to network\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\ntype CandidateNodeVotingRequest struct {\n\tData []byte\n}\n\nfunc (req *CandidateNodeVotingRequest) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading disseminator request\")\n\t\treturn err\n\t}\n\n\treq.Data = slice\n\treturn nil\n}\n\nfunc (req *CandidateNodeVotingRequest) Write(w io.Writer) error {\n\terr := writeSlice(w, req.Data)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on sending disseminator request\")\n\t}\n\n\treturn err\n}\n\ntype CandidateNodeVotingResponse struct {\n\tData []byte\n}\n\nfunc (resp *CandidateNodeVotingResponse) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading CandidateNodeVotingResponse\")\n\t\treturn err\n\t}\n\n\tresp.Data = slice\n\treturn nil\n}\nfunc (resp *CandidateNodeVotingResponse) Write(w io.Writer) error {\n\treturn writeSlice(w, resp.Data)\n}\n\ntype BroadcastNodeConnInfoRequest struct {\n\tData []byte\n}\n\nfunc (req *BroadcastNodeConnInfoRequest) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading disseminator request\")\n\t\treturn err\n\t}\n\n\treq.Data = slice\n\treturn nil\n}\n\nfunc (req *BroadcastNodeConnInfoRequest) Write(w io.Writer) error {\n\terr := writeSlice(w, req.Data)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on sending disseminator request\")\n\t}\n\n\treturn err\n}\n\ntype BroadcastNodeConnInfoResponse struct {\n\tData []byte\n}\n\nfunc (resp *BroadcastNodeConnInfoResponse) Read(r io.Reader) error {\n\tslice, err := ReadSlice(r)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading CandidateNodeVotingResponse\")\n\t\treturn err\n\t}\n\n\tresp.Data = slice\n\treturn nil\n}\nfunc (resp *BroadcastNodeConnInfoResponse) Write(w io.Writer) error {\n\treturn writeSlice(w, resp.Data)\n}\n"
  },
  {
    "path": "packages/network/protocol_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage network\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEmptyGetBodyResponse(t *testing.T) {\n\tbuf := []byte{}\n\tw := bytes.NewBuffer(buf)\n\tempty := &GetBodyResponse{}\n\trequire.NoError(t, empty.Write(w))\n\n\tr := bytes.NewReader(w.Bytes())\n\temptyRes := &GetBodyResponse{}\n\trequire.NoError(t, emptyRes.Read(r))\n}\n\nfunc TestWriteReadInts(t *testing.T) {\n\tbuf := []byte{}\n\tb := bytes.NewBuffer(buf)\n\tst := uint16(2)\n\trequire.NoError(t, binary.Write(b, binary.LittleEndian, st))\n\n\tvar val uint16\n\terr := binary.Read(b, binary.LittleEndian, &val)\n\trequire.NoError(t, err)\n\trequire.Equal(t, val, st)\n\tfmt.Println(val)\n}\n\nfunc TestRequestType(t *testing.T) {\n\trt := RequestType{1}\n\tbuf := []byte{}\n\tb := bytes.NewBuffer(buf)\n\n\tresult := RequestType{}\n\trequire.NoError(t, rt.Write(b))\n\trequire.NoError(t, result.Read(b))\n\trequire.Equal(t, rt, result)\n\tfmt.Println(rt, result)\n\n}\n\nfunc TestGetBodyResponse(t *testing.T) {\n\trt := GetBodyResponse{Data: make([]byte, 4, 4)}\n\tbuf := []byte{}\n\tb := bytes.NewBuffer(buf)\n\n\tresult := GetBodyResponse{}\n\trequire.NoError(t, rt.Write(b))\n\trequire.NoError(t, result.Read(b))\n\trequire.Equal(t, rt, result)\n\tfmt.Println(rt, result)\n\n}\n\nfunc TestBodyResponse(t *testing.T) {\n\trt := GetBodyResponse{Data: []byte(strings.Repeat(\"A\", 32))}\n\tbuf := []byte{}\n\tb := bytes.NewBuffer(buf)\n\n\tresult := &GetBodyResponse{}\n\trequire.NoError(t, rt.Write(b))\n\trequire.NoError(t, result.Read(b))\n\trequire.Equal(t, rt.Data, result.Data)\n\tfmt.Println(rt, result)\n\n}\n"
  },
  {
    "path": "packages/network/tcpclient/blocks_collection.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar ErrorEmptyBlockBody = errors.New(\"block is empty\")\nvar ErrorWrongSizeBytes = errors.New(\"wrong size bytes\")\n\nconst hasVal = \"has value\"\nconst hasntVal = \"has not value\"\n\nconst sizeBytesLength = 4\n\n// GetBlocksBodies send GetBodiesRequest returns channel of binary blocks data\nfunc GetBlocksBodies(ctx context.Context, host string, blockID int64, reverseOrder bool) (<-chan []byte, error) {\n\tconn, err := newConnection(host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// send the type of data\n\trt := &network.RequestType{Type: network.RequestTypeBlockCollection}\n\tif err = rt.Write(conn); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"writing data type block body to connection\")\n\t\treturn nil, err\n\t}\n\n\treq := &network.GetBodiesRequest{\n\t\tBlockID:      uint32(blockID),\n\t\tReverseOrder: reverseOrder,\n\t}\n\n\tif err = req.Write(conn); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on sending blocks bodies request\")\n\t\treturn nil, err\n\t}\n\n\tblocksCount, err := network.ReadInt(conn)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"on getting blocks count\")\n\t\treturn nil, err\n\t}\n\n\tif blocksCount == 0 {\n\t\treturn nil, fmt.Errorf(\"host: %s does'nt contains blocks\", host)\n\t}\n\n\tblocksChan, errChan := GetBlockBodiesChan(ctx, conn, blocksCount)\n\tgo func() {\n\t\tfor err := range errChan {\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"on reading block bodies\")\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn blocksChan, nil\n}\n\nfunc GetBlockBodiesChan(ctx context.Context, src io.ReadCloser, blocksCount int64) (<-chan []byte, <-chan error) {\n\trawBlocksCh := make(chan []byte, blocksCount)\n\terrChan := make(chan error, 1)\n\n\tsizeBuf := make([]byte, sizeBytesLength)\n\tvar bodyBuf []byte\n\n\tafterBodyProcessed := func(done <-chan struct{}) {\n\t\t<-done\n\t\tBytesPool.Put(bodyBuf)\n\t}\n\n\tgo func() {\n\t\tdefer func() {\n\t\t\tclose(rawBlocksCh)\n\t\t\tclose(errChan)\n\t\t\tsrc.Close()\n\t\t\tgo afterBodyProcessed(ctx.Done())\n\t\t}()\n\n\t\tdataSize, err := network.ReadInt(src)\n\t\tif err != nil {\n\t\t\terrChan <- err\n\t\t\treturn\n\t\t}\n\n\t\tbodyBuf = BytesPool.Get(dataSize)\n\t\tvar bodyStartIndx int64\n\n\t\tfor i := 0; i < int(blocksCount); i++ {\n\n\t\t\t_, err := io.ReadFull(src, sizeBuf)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on reading size of block data\")\n\t\t\t\terrChan <- err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tsize, intErr := binary.Uvarint(sizeBuf)\n\t\t\tif intErr < 0 {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": ErrorWrongSizeBytes}).Error(\"on convert size body\")\n\t\t\t\terrChan <- ErrorWrongSizeBytes\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tbodyEndIndx := bodyStartIndx + int64(size)\n\t\t\tbody := bodyBuf[bodyStartIndx:bodyEndIndx]\n\t\t\tif readed, err := io.ReadFull(src, body); err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"size\": size, \"readed\": readed, \"error\": err}).Error(\"on reading block body\")\n\t\t\t\terrChan <- err\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tbodyStartIndx = bodyEndIndx\n\t\t\trawBlocksCh <- body\n\t\t\terrChan <- nil\n\t\t}\n\t}()\n\n\treturn rawBlocksCh, errChan\n}\n"
  },
  {
    "path": "packages/network/tcpclient/candidate_node_voting.go",
    "content": "package tcpclient\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"time\"\n)\n\nfunc UpdateMachineStatus(localAddress, tcpAddress string, logger *log.Entry) ([]byte, error) {\n\tconn, err := newConnection(tcpAddress)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConnectionError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"dialing to host\")\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\n\trt := &network.RequestType{Type: network.RequestTypeVoting}\n\tif err = rt.Write(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending request type\")\n\t\treturn nil, err\n\t}\n\n\tprevBlock := &sqldb.InfoBlock{}\n\t_, err = prevBlock.Get()\n\tNodePrivateKey, NodePublicKey := utils.GetNodeKeys()\n\tif len(NodePrivateKey) < 1 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node private key is empty\")\n\t\treturn nil, errors.New(`node private key is empty`)\n\t}\n\tif len(NodePublicKey) < 1 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node public key is empty\")\n\t\treturn nil, errors.New(`node public key is empty`)\n\t}\n\n\tvoteMsg := &network.VoteMsg{\n\t\tCurrentBlockHeight: prevBlock.BlockID,\n\t\tLocalAddress:       localAddress,\n\t\tTcpAddress:         tcpAddress,\n\t\tEcosystemID:        0,\n\t\tHash:               prevBlock.Hash,\n\t\tTime:               time.Now().UnixMilli(),\n\t}\n\n\tsignStr := voteMsg.VoteForSign()\n\tsigned, err := crypto.SignString(NodePrivateKey, signStr)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"signing voteMsg\")\n\t\treturn nil, err\n\t}\n\tvoteMsg.Sign = signed\n\tdata, err := json.Marshal(voteMsg)\n\tif err != nil {\n\t\tlog.Fatalf(\"VoteMsg JSON marshaling failed: %s\", err)\n\t}\n\n\treq := &network.CandidateNodeVotingRequest{\n\t\tData: data,\n\t}\n\tif err = req.Write(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending voting request\")\n\t\treturn nil, err\n\t}\n\n\tresp := &network.CandidateNodeVotingResponse{}\n\tif err := resp.Read(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"receiving voting response\")\n\t\treturn nil, err\n\t}\n\n\treturn resp.Data, nil\n}\n\nfunc BroadcastNodeConnInfo(tcpAddress string, data []byte, logger *log.Entry) error {\n\tconn, err := newConnection(tcpAddress)\n\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConnectionError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"dialing to host\")\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\trt := &network.RequestType{Type: network.RequestSyncMatchineState}\n\tif err = rt.Write(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending request type\")\n\t\treturn err\n\t}\n\treq := &network.BroadcastNodeConnInfoRequest{\n\t\tData: data,\n\t}\n\tif err = req.Write(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"tcpAddress\": tcpAddress}).Error(\"sending voting request\")\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/network/tcpclient/client.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar wrongAddressError = errors.New(\"Wrong address\")\n\n// NormalizeHostAddress get address. if port not defined returns combined string with ip and defaultPort\nfunc NormalizeHostAddress(address string, defaultPort int64) (string, error) {\n\n\t_, _, err := net.SplitHostPort(address)\n\tif err != nil {\n\t\tif strings.HasSuffix(err.Error(), \"missing port in address\") {\n\t\t\treturn fmt.Sprintf(\"%s:%d\", address, defaultPort), nil\n\t\t}\n\n\t\treturn \"\", err\n\t}\n\n\treturn address, nil\n}\n\nfunc newConnection(addr string) (net.Conn, error) {\n\tif len(addr) == 0 {\n\t\treturn nil, wrongAddressError\n\t}\n\n\thost, err := NormalizeHostAddress(addr, consts.DefaultTcpPort)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"host\": addr, \"error\": err}).Error(\"on normalize host address\")\n\t\treturn nil, err\n\t}\n\n\tconn, err := net.DialTimeout(\"tcp\", host, consts.TCPConnTimeout)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConnectionError, \"error\": err, \"address\": host}).Debug(\"dialing tcp\")\n\t\treturn nil, err\n\t}\n\n\tconn.SetReadDeadline(time.Now().Add(consts.ReadTimeout * time.Second))\n\tconn.SetWriteDeadline(time.Now().Add(consts.WriteTimeout * time.Second))\n\treturn conn, nil\n}\n"
  },
  {
    "path": "packages/network/tcpclient/client_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t_ \"net/http/pprof\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n)\n\nvar inputs = make([][]byte, 0, 100)\n\nfunc init() {\n\tfor i := 0; i < 100; i++ {\n\t\tinputs = append(inputs, []byte(strings.Repeat(\"B\", rand.Intn(194334))))\n\t}\n}\n\ntype BufCloser struct {\n\t*bytes.Buffer\n}\n\nfunc (bc BufCloser) Close() error {\n\tbc.Reset()\n\treturn nil\n}\n\nfunc BenchmarkGetBlockBodiesWithChanReadAll(t *testing.B) {\n\tvar bts []byte\n\tr := BufCloser{bytes.NewBuffer(bts)}\n\n\t// dataLen := 4\n\tt.ResetTimer()\n\tfor j := 0; j < t.N; j++ {\n\t\tt.StopTimer()\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tresp := network.GetBodyResponse{\n\t\t\t\tData: inputs[i],\n\t\t\t}\n\n\t\t\tresp.Write(r)\n\t\t}\n\n\t\t//ctxDone, cancel := context.WithCancel(context.Background())\n\n\t\tt.StartTimer()\n\t\t//blocksC, errC := GetBlockBodiesChanReadAll(ctxDone, r, 100)\n\t\t// blocksC, errC := GetBlockBodiesChan(ctxDone, r, 100)\n\t\t//go func() {\n\t\t//\terr := <-errC\n\t\t//\tif err != nil {\n\t\t//\t\tfmt.Println(err)\n\t\t//\t}\n\t\t//}()\n\t\t//\n\t\t//for item := range blocksC {\n\t\t//\titem = item[:0]\n\t\t//}\n\t\t//cancel()\n\t}\n}\n\n//===================================================GetBlockBodiesChanByBlock\n\n// 500\t   2264475 ns/op\t  109001 B/op\t     108 allocs/op with pool size 12832256\nfunc BenchmarkGetBlockBodiesChanByBlockWithSyncPool(t *testing.B) {\n\tvar bts []byte\n\tr := BufCloser{bytes.NewBuffer(bts)}\n\n\tt.ResetTimer()\n\tfor j := 0; j < t.N; j++ {\n\t\tt.StopTimer()\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tresp := network.GetBodyResponse{\n\t\t\t\tData: inputs[i],\n\t\t\t}\n\n\t\t\t// fmt.Println(\"lenData\", len(inputs[i]))\n\t\t\tresp.Write(r)\n\t\t}\n\n\t\t//ctxDone, cancel := context.WithCancel(context.Background())\n\t\t//\n\t\t//t.StartTimer()\n\t\t//blocksC, errC := GetBlockBodiesChanByBlock(ctxDone, r, 100)\n\t\t//\n\t\t//go func() {\n\t\t//\terr := <-errC\n\t\t//\tif err != nil {\n\t\t//\t\tfmt.Println(err)\n\t\t//\t}\n\t\t//}()\n\t\t//\n\t\t//for item := range blocksC {\n\t\t//\titem = item[:0]\n\t\t//}\n\t\t//cancel()\n\t}\n\n}\n\nfunc BenchmarkGetBlockBodiesChanByBlockWithBytePool(t *testing.B) {\n\tvar bts []byte\n\tr := BufCloser{bytes.NewBuffer(bts)}\n\n\tt.ResetTimer()\n\tfor j := 0; j < t.N; j++ {\n\t\tt.StopTimer()\n\n\t\tvar dataSize int64\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tdataSize += int64(len(inputs[i]))\n\t\t}\n\t\tnetwork.WriteInt(dataSize, r)\n\t\t// fmt.Println(\"sending data size\", dataSize)\n\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tresp := network.GetBodyResponse{\n\t\t\t\tData: inputs[i],\n\t\t\t}\n\n\t\t\t// fmt.Println(\"lenData\", len(inputs[i]))\n\t\t\tresp.Write(r)\n\t\t}\n\n\t\t//ctxDone, cancel := context.WithCancel(context.Background())\n\t\t//\n\t\t//t.StartTimer()\n\t\t//blocksC, errC := GetBlockBodiesChanByBlockWithBytePool(ctxDone, r, 100)\n\t\t//\n\t\t//go func() {\n\t\t//\terr := <-errC\n\t\t//\tif err != nil {\n\t\t//\t\tfmt.Println(err)\n\t\t//\t}\n\t\t//}()\n\t\t//\n\t\t//for item := range blocksC {\n\t\t//\t// fmt.Println(len(item))\n\t\t//\titem = item[:0]\n\t\t//}\n\t\t//cancel()\n\t}\n}\n\nfunc BenchmarkGetBlockBodiesWithChanReadToStruct(t *testing.B) {\n\tvar bts []byte\n\tr := BufCloser{bytes.NewBuffer(bts)}\n\n\tt.ResetTimer()\n\tfor j := 0; j < t.N; j++ {\n\t\tt.StopTimer()\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tresp := network.GetBodyResponse{\n\t\t\t\tData: inputs[i],\n\t\t\t}\n\n\t\t\t// fmt.Println(\"lenData\", len(inputs[i]))\n\t\t\tresp.Write(r)\n\t\t}\n\n\t\tctx := context.Background()\n\n\t\tt.StartTimer()\n\t\tblocksC, errC := GetBlockBodiesChan(ctx, r, 100)\n\n\t\tgo func() {\n\t\t\terr := <-errC\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(err)\n\t\t\t}\n\t\t}()\n\n\t\tfor item := range blocksC {\n\t\t\titem = item[:0]\n\t\t}\n\t}\n}\n\nfunc BenchmarkGetBlockBodiesAsSlice(t *testing.B) {\n\tvar bts []byte\n\tr := BufCloser{bytes.NewBuffer(bts)}\n\n\t// dataLen := 4\n\tt.ResetTimer()\n\tfor j := 0; j < t.N; j++ {\n\t\tt.StopTimer()\n\t\tfor i := 0; i < 100; i++ {\n\t\t\tresp := network.GetBodyResponse{\n\t\t\t\tData: inputs[i],\n\t\t\t}\n\n\t\t\tresp.Write(r)\n\t\t}\n\n\t\t//ctxDone, cancel := context.WithCancel(context.Background())\n\t\t//\n\t\t//t.StartTimer()\n\t\t//blocks, err := GetBlockBodiesReadAll(ctxDone, r, 100)\n\t\t//if err != nil {\n\t\t//\tfmt.Println(err)\n\t\t//}\n\t\t//\n\t\t//for i := 0; i < len(blocks); i++ {\n\t\t//\tblocks[i] = blocks[i][:0]\n\t\t//}\n\t\t//cancel()\n\t}\n}\n\n//==============================================\n// func TestReadSize(t *testing.T) {\n// \tbts := []byte{}\n// \tbuf := bytes.NewBuffer(bts)\n\n// \tresp := network.GetBodyResponse{\n// \t\tData: []byte(strings.Repeat(\"B\", 152627)),\n// \t}\n\n// \tresp.Write(buf)\n\n// \tval, err := binary.ReadUvarint(buf)\n// \trequire.NoError(t, err)\n// \tfmt.Println(val)\n// \t// data := buf.Bytes()\n// \t// size, intErr := binary.Uvarint(data[:4])\n// \t// fmt.Println(size, intErr)\n\n// }\n\n// func TestBinary(t *testing.T) {\n\n// \tbuf := []byte{}\n// \tbb := bytes.NewBuffer(buf)\n// \tfor _, x := range []uint64{1, 2, 127, 128, 255, 152627} {\n// \t\tmb := make([]byte, 4)\n// \t\t_ = binary.PutUvarint(mb, x)\n// \t\tbb.Write(mb)\n// \t\t// fmt.Printf(\"%x\\n\", buf[:n])\n// \t}\n\n// \tresBts := bb.Bytes()\n// \tfmt.Println(resBts)\n// \tvar pos int\n// \tfor i := 0; i < 6; i++ {\n// \t\tvalBts := resBts[pos : pos+4]\n// \t\tpos += 4\n// \t\tfmt.Println(\"valBts\", valBts)\n// \t\tvalue, re := binary.Uvarint(valBts)\n// \t\tfmt.Println(value, \"readed\", re)\n// \t}\n// }\n\n// //100000\t     17333 ns/op\t     576 B/op\t      19 allocs/op\n\n// func BenchmarkGetBlockBodiesWithBuffer(t *testing.B) {\n// \tctx := context.Background()\n// \tvar bts []byte\n// \tr := BufCloser{\n// \t\tBuffer: bytes.NewBuffer(bts),\n// \t}\n\n// \tbyteString := []byte(strings.Repeat(\"A\", 32))\n// \tt.ResetTimer()\n// \tfor j := 0; j < t.N; j++ {\n// \t\tt.StopTimer()\n// \t\tfor i := 0; i < 5; i++ {\n// \t\t\tresp := network.GetBodyResponse{\n// \t\t\t\tData: byteString,\n// \t\t\t}\n\n// \t\t\tresp.Write(r)\n// \t\t}\n// \t\tfmt.Println(\"[\", j, \"]\")\n// \t\tt.StartTimer()\n\n// \t\tblocksC, errC := GetBlockBodiesChanWithPool(ctx, r, 5)\n// \t\tgo func() {\n// \t\t\terr := <-errC\n// \t\t\tif err != nil {\n// \t\t\t\tfmt.Println(err)\n// \t\t\t}\n// \t\t}()\n\n// \t\tfor item := range blocksC {\n// \t\t\tfmt.Println(string(item))\n// \t\t\tBlockBodyPool.putBytes(item)\n// \t\t}\n\n// \t}\n// }\n"
  },
  {
    "path": "packages/network/tcpclient/confirmation.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc CheckConfirmation(host string, blockID int64, logger *log.Entry) (hash string) {\n\tconn, err := newConnection(host)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConnectionError, \"error\": err, \"host\": host, \"block_id\": blockID}).Debug(\"dialing to host\")\n\t\treturn \"0\"\n\t}\n\tdefer conn.Close()\n\n\trt := &network.RequestType{Type: network.RequestTypeConfirmation}\n\tif err = rt.Write(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"host\": host, \"block_id\": blockID}).Error(\"sending request type\")\n\t\treturn \"0\"\n\t}\n\n\treq := &network.ConfirmRequest{\n\t\tBlockID: uint32(blockID),\n\t}\n\tif err = req.Write(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"host\": host, \"block_id\": blockID}).Error(\"sending confirmation request\")\n\t\treturn \"0\"\n\t}\n\n\tresp := &network.ConfirmResponse{}\n\n\tif err := resp.Read(conn); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"host\": host, \"block_id\": blockID}).Error(\"receiving confirmation response\")\n\t\treturn \"0\"\n\t}\n\treturn string(converter.BinToHex(resp.Hash))\n}\n"
  },
  {
    "path": "packages/network/tcpclient/disseminator.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar (\n\tErrNodesUnavailable = errors.New(\"All nodes unvailabale\")\n)\n\nfunc sendRawTransacitionsToHost(host string, packet []byte) error {\n\tcon, err := newConnection(host)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"host\": host}).Error(\"on creating tcp connection\")\n\t\treturn err\n\t}\n\n\tdefer con.Close()\n\n\tif err := sendDisseminatorRequest(con, network.RequestTypeNotHonorNode, packet); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.TCPClientError, \"error\": err, \"host\": host}).Error(\"on sending disseminator request\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc SendTransacitionsToAll(ctx context.Context, hosts []string, txes []sqldb.Transaction) error {\n\tif len(hosts) == 0 || len(txes) == 0 {\n\t\treturn nil\n\t}\n\n\tpacket, err := MarshalTxPacket(txes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar wg sync.WaitGroup\n\tvar errCount int32\n\tfor _, h := range hosts {\n\t\tif err := ctx.Err(); err != nil {\n\t\t\tlog.Debug(\"exit by context error\")\n\t\t\treturn err\n\t\t}\n\n\t\twg.Add(1)\n\t\tgo func(host string, pak []byte) {\n\t\t\tdefer wg.Done()\n\n\t\t\tif err := sendRawTransacitionsToHost(host, pak); err != nil {\n\t\t\t\tatomic.AddInt32(&errCount, 1)\n\t\t\t}\n\t\t}(h, packet)\n\t}\n\n\twg.Wait()\n\n\tif int(errCount) == len(hosts) {\n\t\treturn ErrNodesUnavailable\n\t}\n\n\treturn nil\n}\n\nfunc SendFullBlockToAll(ctx context.Context, hosts []string, block *sqldb.InfoBlock, txes []sqldb.Transaction, nodeID int64) error {\n\tif len(hosts) == 0 {\n\t\treturn nil\n\t}\n\n\treq := prepareFullBlockRequest(block, txes, nodeID)\n\ttxDataMap := make(map[string][]byte, len(txes))\n\tfor _, tx := range txes {\n\t\ttxDataMap[string(tx.Hash)] = tx.Data\n\t}\n\n\tvar errCount int32\n\tincreaseErrCount := func() {\n\t\tatomic.AddInt32(&errCount, 1)\n\t}\n\n\tvar wg sync.WaitGroup\n\tfor _, host := range hosts {\n\t\twg.Add(1)\n\n\t\tgo func(h string) {\n\t\t\tdefer wg.Done()\n\n\t\t\tcon, err := newConnection(h)\n\t\t\tif err != nil {\n\t\t\t\tincreaseErrCount()\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"host\": h}).Error(\"on creating tcp connection\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdefer con.Close()\n\n\t\t\tresponse, err := sendFullBlockRequest(con, req)\n\t\t\tif err != nil {\n\t\t\t\tincreaseErrCount()\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err, \"host\": h}).Error(\"on sending full block request\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif len(response) == 0 || len(response) < consts.HashSize {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar buf bytes.Buffer\n\t\t\trequestedHashes := parseTxHashesFromResponse(response)\n\t\t\tfor _, txhash := range requestedHashes {\n\t\t\t\tif data, ok := txDataMap[string(txhash)]; ok && len(data) > 0 {\n\t\t\t\t\tlog.WithFields(log.Fields{\"len_of_tx\": len(data)}).Debug(\"on prepare full tx package\")\n\t\t\t\t\tif _, err := buf.Write(converter.EncodeLengthPlusData(data)); err != nil {\n\t\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Warn(\"on write tx hash to response buffer\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif _, err = con.Write(converter.DecToBin(buf.Len(), 4)); err != nil {\n\t\t\t\tincreaseErrCount()\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"host\": h}).Error(\"on writing requested transactions buf length\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif _, err = con.Write(buf.Bytes()); err != nil {\n\t\t\t\tincreaseErrCount()\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err, \"host\": h}).Error(\"on writing requested transactions\")\n\t\t\t\treturn\n\t\t\t}\n\t\t}(host)\n\t}\n\n\twg.Wait()\n\n\tif int(errCount) == len(hosts) {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"err_count\": errCount}).Error(ErrNodesUnavailable)\n\t\treturn ErrNodesUnavailable\n\t}\n\n\treturn nil\n}\n\nfunc sendFullBlockRequest(con net.Conn, data []byte) (response []byte, err error) {\n\n\tif err := sendDisseminatorRequest(con, network.RequestTypeHonorNode, data); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.TCPClientError, \"error\": err}).Error(\"on sending disseminator request\")\n\t\treturn nil, err\n\t}\n\n\t//response\n\treturn resieveRequiredTransactions(con)\n}\n\nfunc MarshalTxPacket(txes []sqldb.Transaction) ([]byte, error) {\n\tdat := make([][]byte, 0)\n\tfor _, tr := range txes {\n\t\tdat = append(dat, tr.Data)\n\t}\n\treturn json.Marshal(dat)\n}\n\n//func prepareTxPacket(txes []sqldb.Transaction) []byte {\n//\t// form packet to send\n//\tvar buf bytes.Buffer\n//\tfor _, tr := range txes {\n//\t\tbuf.Write(tr.Data)\n//\t}\n//\n//\treturn buf.Bytes()\n//}\n\nfunc prepareFullBlockRequest(block *sqldb.InfoBlock, trs []sqldb.Transaction, nodeID int64) []byte {\n\tvar noBlockFlag byte\n\tif block == nil {\n\t\tnoBlockFlag = 1\n\t}\n\n\tvar buf bytes.Buffer\n\tbuf.Write(converter.DecToBin(nodeID, 8))\n\tbuf.WriteByte(noBlockFlag)\n\tif noBlockFlag == 0 {\n\t\tbuf.Write(block.Marshall())\n\t}\n\tif trs != nil {\n\t\tfor _, tr := range trs {\n\t\t\tbuf.Write(tr.Hash)\n\t\t}\n\t}\n\n\treturn buf.Bytes()\n}\n\nfunc resieveRequiredTransactions(con net.Conn) (response []byte, err error) {\n\tneedTxResp := network.DisHashResponse{}\n\tif err := needTxResp.Read(con); err != nil {\n\t\tif err == io.EOF {\n\t\t\treturn nil, nil\n\t\t}\n\t\tif err == network.ErrMaxSize {\n\t\t\tlog.WithFields(log.Fields{\"max_size\": syspar.GetMaxTxSize(), \"type\": consts.ParameterExceeded}).Warning(\"response size is larger than max tx size\")\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading data\")\n\t\treturn nil, err\n\t}\n\n\treturn needTxResp.Data, err\n}\n\nfunc parseTxHashesFromResponse(resp []byte) (hashes [][]byte) {\n\thashes = make([][]byte, 0, len(resp)/consts.HashSize)\n\tfor len(resp) >= consts.HashSize {\n\t\thashes = append(hashes, converter.BytesShift(&resp, consts.HashSize))\n\t}\n\n\treturn\n}\n\nfunc sendDisseminatorRequest(con net.Conn, requestType network.ReqTypesFlag, packet []byte) (err error) {\n\t/*\n\t\tPacket format:\n\t\ttype  2 bytes\n\t\tlen   4 bytes\n\t\tdata  len bytes\n\t*/\n\t// type\n\trt := network.RequestType{\n\t\tType: requestType,\n\t}\n\terr = rt.Write(con)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"writing request type to host\")\n\t\treturn err\n\t}\n\n\t// data size\n\t// size := converter.DecToBin(len(packet), 4)\n\t// _, err = con.Write(size)\n\t// if err != nil {\n\t// \tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"writing data size to host\")\n\t// \treturn err\n\t// }\n\n\t// // data\n\t// _, err = con.Write(packet)\n\t// if err != nil {\n\t// \tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"writing data to host\")\n\t// \treturn err\n\t// }\n\n\treq := network.DisRequest{\n\t\tData: packet,\n\t}\n\n\treturn req.Write(con)\n}\n"
  },
  {
    "path": "packages/network/tcpclient/max_block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc HostWithMaxBlock(ctx context.Context, hosts []string) (bestHost string, maxBlockID int64, err error) {\n\tif len(hosts) == 0 {\n\t\treturn \"\", -1, nil\n\t}\n\n\treturn hostWithMaxBlock(ctx, hosts)\n}\n\nfunc GetMaxBlockID(host string) (blockID int64, err error) {\n\treturn getMaxBlock(host)\n}\n\nfunc getMaxBlock(host string) (blockID int64, err error) {\n\tcon, err := newConnection(host)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.ConnectionError, \"host\": host}).Debug(\"error connecting to host\")\n\t\treturn -1, err\n\t}\n\tdefer con.Close()\n\n\t// send max block request\n\trt := &network.RequestType{\n\t\tType: network.RequestTypeMaxBlock,\n\t}\n\n\tif err := rt.Write(con); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.ConnectionError, \"host\": host}).Error(\"on sending Max block request type\")\n\t\treturn -1, err\n\t}\n\n\t// response\n\tresp := network.MaxBlockResponse{}\n\terr = resp.Read(con)\n\tif err == io.EOF {\n\t} else if err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.ConnectionError, \"host\": host}).Error(\"reading max block id from host\")\n\t\treturn -1, err\n\t}\n\n\treturn resp.BlockID, nil\n}\n\nfunc hostWithMaxBlock(ctx context.Context, hosts []string) (bestHost string, maxBlockID int64, err error) {\n\tmaxBlockID = -1\n\n\ttype blockAndHost struct {\n\t\thost    string\n\t\tblockID int64\n\t\terr     error\n\t}\n\n\tresultChan := make(chan blockAndHost, len(hosts))\n\n\t/* rand.Shuffle(len(hosts), func(i, j int) { hosts[i], hosts[j] = hosts[j], hosts[i] })\n\tthis implementation available only in Golang 1.10\n\t*/\n\tutils.ShuffleSlice(hosts)\n\n\tvar wg sync.WaitGroup\n\tfor _, h := range hosts {\n\t\tif ctx.Err() != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": ctx.Err(), \"type\": consts.ContextError}).Error(\"context error\")\n\t\t\treturn \"\", maxBlockID, ctx.Err()\n\t\t}\n\n\t\twg.Add(1)\n\n\t\tgo func(host string) {\n\t\t\tblockID, err := getMaxBlock(host)\n\t\t\tdefer wg.Done()\n\n\t\t\tresultChan <- blockAndHost{\n\t\t\t\thost:    host,\n\t\t\t\tblockID: blockID,\n\t\t\t\terr:     err,\n\t\t\t}\n\t\t}(h)\n\t}\n\twg.Wait()\n\n\tvar errCount int\n\tfor i := 0; i < len(hosts); i++ {\n\t\tbl := <-resultChan\n\n\t\tif bl.err != nil {\n\t\t\terrCount++\n\t\t\tcontinue\n\t\t}\n\n\t\t// If blockID is maximal then the current host is the best\n\t\tif bl.blockID > maxBlockID {\n\t\t\tmaxBlockID = bl.blockID\n\t\t\tbestHost = bl.host\n\t\t}\n\t}\n\n\tif errCount == len(hosts) {\n\t\treturn \"\", 0, ErrNodesUnavailable\n\t}\n\n\treturn bestHost, maxBlockID, nil\n}\n"
  },
  {
    "path": "packages/network/tcpclient/pools.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"sync\"\n)\n\n// return nearest power of 2 that bigest than v\nfunc powerOfTwo(v int) int64 {\n\tv--\n\tv |= v >> 1\n\tv |= v >> 2\n\tv |= v >> 4\n\tv |= v >> 8\n\tv |= v >> 16\n\tv++\n\treturn int64(v)\n}\n\nvar BytesPool *bytePool\n\nfunc init() {\n\tBytesPool = &bytePool{\n\t\tpools: make(map[int64]*sync.Pool),\n\t}\n}\n\ntype bytePool struct {\n\tpools map[int64]*sync.Pool\n}\n\nfunc (p *bytePool) Get(size int64) []byte {\n\tpower := powerOfTwo(int(size))\n\tif pool, ok := p.pools[power]; ok {\n\t\treturn pool.Get().([]byte)\n\t}\n\n\tpool := &sync.Pool{\n\t\tNew: func() any { return make([]byte, power) },\n\t}\n\n\tp.pools[power] = pool\n\treturn pool.Get().([]byte)\n}\n\nfunc (p *bytePool) Put(buf []byte) {\n\tif len(buf) == 0 {\n\t\treturn\n\t}\n\n\tif pool, ok := p.pools[int64(len(buf))]; ok {\n\t\tpool.Put(buf)\n\t}\n}\n"
  },
  {
    "path": "packages/network/tcpclient/pools_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBytesPoolGet(t *testing.T) {\n\n\tbuf := BytesPool.Get(12832256)\n\trequire.Equal(t, 16777216, len(buf))\n}\n\nfunc TestBytesPoolPut(t *testing.T) {\n\tshort := []byte(strings.Repeat(\"A\", 5))\n\tbuf := BytesPool.Get(12832256)\n\tcopy(buf[:5], short)\n\tBytesPool.Put(buf)\n\n\tnewBuf := BytesPool.Get(12832256)\n\trequire.Equal(t, 16777216, len(newBuf))\n\n\trequire.Equal(t, newBuf[:5], short)\n\tfmt.Println(newBuf[:6])\n}\n\nfunc TestBytesPoolCicle(t *testing.T) {\n\tshort := []byte(strings.Repeat(\"A\", 5))\n\tbuf := BytesPool.Get(int64(len(short)))\n\tcopy(buf[:5], short)\n\tBytesPool.Put(buf)\n\n\tpower := powerOfTwo(5)\n\tfmt.Println(\"power\", power)\n\n\tnewBuf := BytesPool.Get(5)\n\trequire.Equal(t, power, int64(len(newBuf)))\n\n\trequire.Equal(t, newBuf[:5], short)\n\tfmt.Println(newBuf)\n}\n"
  },
  {
    "path": "packages/network/tcpclient/stop_network.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpclient\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n)\n\nfunc SendStopNetwork(addr string, req *network.StopNetworkRequest) error {\n\tconn, err := newConnection(addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer conn.Close()\n\n\trt := &network.RequestType{\n\t\tType: network.RequestTypeStopNetwork,\n\t}\n\n\tif err = rt.Write(conn); err != nil {\n\t\treturn err\n\t}\n\n\tif err = req.Write(conn); err != nil {\n\t\treturn err\n\t}\n\n\tres := &network.StopNetworkResponse{}\n\tif err = res.Read(conn); err != nil {\n\t\treturn err\n\t}\n\n\tif len(res.Hash) != consts.HashSize {\n\t\treturn network.ErrNotAccepted\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/network/tcpserver/blocks_collection.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"net\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// BlockCollection writes the body of the specified block\n// blocksCollection and queue_parser_blocks daemons send the request through p.GetBlocks()\nfunc BlockCollection(request *network.GetBodiesRequest, w net.Conn) error {\n\tblock := &sqldb.BlockChain{}\n\n\tvar blocks []sqldb.BlockChain\n\tvar err error\n\tif request.ReverseOrder {\n\t\tblocks, err = block.GetReverseBlockchain(int64(request.BlockID), network.BlocksPerRequest)\n\t} else {\n\t\tblocks, err = block.GetBlocksFrom(int64(request.BlockID-1), \"ASC\", network.BlocksPerRequest)\n\t}\n\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"block_id\": request.BlockID}).Error(\"Error getting 1000 blocks from block_id\")\n\t\tif err := network.WriteInt(0, w); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"on sending 0 requested blocks\")\n\t\t}\n\t\treturn err\n\t}\n\n\tif err := network.WriteInt(int64(len(blocks)), w); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"on sending requested blocks count\")\n\t\treturn err\n\t}\n\n\tif err := network.WriteInt(lenOfBlockData(blocks), w); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"on sending requested blocks data length\")\n\t\treturn err\n\t}\n\n\tfor _, b := range blocks {\n\t\tbr := &network.GetBodyResponse{Data: b.Data}\n\t\tif err := br.Write(w); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc lenOfBlockData(blocks []sqldb.BlockChain) int64 {\n\tvar length int64\n\tfor i := 0; i < len(blocks); i++ {\n\t\tlength += int64(len(blocks[i].Data))\n\t}\n\n\treturn length\n}\n"
  },
  {
    "path": "packages/network/tcpserver/candidate_node_voting.go",
    "content": "package tcpserver\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"time\"\n)\n\nfunc CandidateNodeVoting(r *network.CandidateNodeVotingRequest) (*network.CandidateNodeVotingResponse, error) {\n\tresp := &network.CandidateNodeVotingResponse{}\n\tvoteMsg := &network.VoteMsg{}\n\terr := json.Unmarshal(r.Data, voteMsg)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"JSONUnmarshallError\")\n\t\treturn nil, err\n\t}\n\tvoteMsg, err = checkClientVote(r, voteMsg)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": \"CheckVote\", \"error\": err}).Error(\"check vote error\")\n\t\treturn nil, err\n\t}\n\tdata, err := json.Marshal(voteMsg)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"JSONMarshallError\")\n\t\treturn nil, err\n\t}\n\tresp.Data = data\n\treturn resp, nil\n}\n\ntype VotingRes struct {\n\tVoteMsgInfo network.VoteMsg `json:\"voteMsgInfo\"`\n\tErr         string          `json:\"err\"`\n}\ntype VotingTotal struct {\n\tData          map[string]VotingRes `json:\"data\"`\n\tAgreeQuantity int64                `json:\"agreeQuantity\"`\n\tLocalAddress  string               `json:\"localAddress\"`\n\tSt            int64                `json:\"st\"`\n}\n\nfunc SyncMatchineStateRes(request *network.BroadcastNodeConnInfoRequest) (*network.BroadcastNodeConnInfoResponse, error) {\n\tresp := &network.BroadcastNodeConnInfoResponse{}\n\tvar votingTotal VotingTotal\n\n\terr := json.Unmarshal(request.Data, &votingTotal)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err}).Error(\"unmarshal voting total\")\n\t\treturn nil, err\n\t}\n\tif votingTotal.AgreeQuantity > 0 {\n\t\tcandidateNode := &sqldb.CandidateNode{\n\t\t\tTcpAddress:     votingTotal.LocalAddress,\n\t\t\tReplyCount:     votingTotal.AgreeQuantity,\n\t\t\tDateReply:      votingTotal.St,\n\t\t\tCandidateNodes: request.Data,\n\t\t}\n\t\terr = candidateNode.UpdateCandidateNodeInfo()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"update candidate honor voting\")\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn resp, nil\n}\n\nfunc checkClientVote(r *network.CandidateNodeVotingRequest, voteMsgParam *network.VoteMsg) (*network.VoteMsg, error) {\n\tvar (\n\t\tprevBlock        = &sqldb.InfoBlock{}\n\t\tst               = time.Now()\n\t\tcandidateNodeSql = &sqldb.CandidateNode{}\n\t)\n\t_, err := prevBlock.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting previous block\")\n\t\treturn nil, err\n\t}\n\tvoteMsg := &network.VoteMsg{\n\t\tCurrentBlockHeight: prevBlock.BlockID,\n\t\tLocalAddress:       voteMsgParam.LocalAddress,\n\t\tTcpAddress:         voteMsgParam.TcpAddress,\n\t\tEcosystemID:        0,\n\t\tHash:               prevBlock.Hash,\n\t\tTime:               time.Now().UnixMilli(),\n\t}\n\tif voteMsgParam.CurrentBlockHeight < prevBlock.BlockID {\n\t\tvoteMsg.Msg = \"Not synced to latest block\"\n\t\tvoteMsg.Agree = false\n\t\tsigned, err := sign(voteMsg)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvoteMsg.Sign = signed\n\t\treturn voteMsg, nil\n\t}\n\ttimeVerification := st.After(time.Unix(voteMsgParam.Time, 0))\n\tif timeVerification {\n\t\tvoteMsg.Msg = \"Time verification failed\"\n\t\tvoteMsg.Agree = false\n\t\tsigned, err := sign(voteMsg)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvoteMsg.Sign = signed\n\t\treturn voteMsg, nil\n\t}\n\terr = candidateNodeSql.GetCandidateNodeByAddress(voteMsgParam.LocalAddress)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpk, err := hex.DecodeString(candidateNodeSql.NodePubKey)\n\tpk = crypto.CutPub(pk)\n\t_, err = crypto.Verify(pk, []byte(voteMsgParam.VoteForSign()), voteMsgParam.Sign)\n\tif err != nil {\n\t\tvoteMsg.Msg = \"Signature verification failed\"\n\t\tvoteMsg.Agree = false\n\t\treturn voteMsg, nil\n\t}\n\tvoteMsg.Msg = \"Passed the verification\"\n\tvoteMsg.Agree = true\n\tsigned, err := sign(voteMsg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvoteMsg.Sign = signed\n\n\treturn voteMsg, nil\n}\n\nfunc sign(voteMsg *network.VoteMsg) ([]byte, error) {\n\tNodePrivateKey, _ := utils.GetNodeKeys()\n\tif len(NodePrivateKey) < 1 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node private key is empty\")\n\t\treturn nil, errors.New(`node private key is empty`)\n\t}\n\tsignStr := voteMsg.VerifyVoteForSign()\n\tsigned, err := crypto.SignString(NodePrivateKey, signStr)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"verify voting signature\")\n\t\treturn nil, err\n\t}\n\n\treturn signed, nil\n}\n"
  },
  {
    "path": "packages/network/tcpserver/confirmation.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Confirmation writes the hash of the specified block\n// The request is sent by 'confirmations' daemon\nfunc Confirmation(r *network.ConfirmRequest) (*network.ConfirmResponse, error) {\n\tresp := &network.ConfirmResponse{}\n\tblock := &sqldb.BlockChain{}\n\tfound, err := block.Get(int64(r.BlockID))\n\tif err != nil || !found {\n\t\thash := [32]byte{}\n\t\tresp.Hash = hash[:]\n\t} else {\n\t\tresp.Hash = block.Hash // can we send binary data ?\n\t}\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"block_id\": r.BlockID}).Error(\"Getting block\")\n\t} else if len(block.Hash) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"block_id\": r.BlockID}).Warning(\"Block not found\")\n\t}\n\treturn resp, nil\n}\n"
  },
  {
    "path": "packages/network/tcpserver/disseminate_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"bytes\"\n\tcrand \"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"encoding/pem\"\n\t\"io\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/symalgo/aes\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// DisseminateTxs serves requests from disseminator for tx\nfunc DisseminateTxs(rw io.ReadWriter) error {\n\tr := &network.DisRequest{}\n\tif err := r.Read(rw); err != nil {\n\t\treturn err\n\t}\n\n\ttxs, err := UnmarshalTxPacket(r.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar rtxs []*sqldb.RawTx\n\tfor _, tran := range txs {\n\t\tif int64(len(tran)) > syspar.GetMaxTxSize() {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"max_tx_size\": syspar.GetMaxTxSize(), \"current_size\": len(tran)}).Error(\"transaction size exceeds max size\")\n\t\t\treturn utils.ErrInfo(\"len(txBinData) > max_tx_size\")\n\t\t}\n\n\t\tif tran == nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"mx_tx_size\": syspar.GetMaxTxSize(), \"info\": \"tran nil\", \"current_size\": len(tran)}).Error(\"transaction size nil\")\n\t\t\tcontinue\n\t\t}\n\n\t\trtx := &transaction.Transaction{}\n\t\tif err = rtx.Unmarshall(bytes.NewBuffer(tran), true); err != nil {\n\t\t\treturn err\n\t\t}\n\t\trtxs = append(rtxs, rtx.SetRawTx())\n\t}\n\n\terr = sqldb.SendTxBatches(rtxs)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n//// Type2 serves requests from disseminator\n//func Type2(rw io.ReadWriter) (*network.DisTrResponse, error) {\n//\tr := &network.DisRequest{}\n//\tif err := r.Read(rw); err != nil {\n//\t\treturn nil, err\n//\t}\n//\n//\tbinaryData := r.Data\n//\t// take the transactions from usual users but not nodes.\n//\t_, _, decryptedBinData, err := DecryptData(&binaryData)\n//\tif err != nil {\n//\t\treturn nil, utils.ErrInfo(err)\n//\t}\n//\n//\tif int64(len(binaryData)) > syspar.GetMaxTxSize() {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"max_size\": syspar.GetMaxTxSize(), \"size\": len(binaryData)}).Error(\"transaction size exceeds max size\")\n//\t\treturn nil, utils.ErrInfo(\"len(txBinData) > max_tx_size\")\n//\t}\n//\n//\tif len(binaryData) < 5 {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.ProtocolError, \"len\": len(binaryData), \"should_be_equal\": 5}).Error(\"binary data slice has incorrect length\")\n//\t\treturn nil, utils.ErrInfo(\"len(binaryData) < 5\")\n//\t}\n//\n//\ttx := transaction.Transaction{}\n//\tif err = tx.Unmarshall(bytes.NewBuffer(decryptedBinData)); err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err}).Error(\"unmarshalling transaction\")\n//\t\treturn nil, err\n//\t}\n//\n//\t_, err = sqldb.DeleteQueueTxByHash(nil, tx.Hash())\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"hash\": tx.Hash()}).Error(\"Deleting queue_tx with hash\")\n//\t\treturn nil, utils.ErrInfo(err)\n//\t}\n//\n//\tqueueTx := &sqldb.QueueTx{Hash: tx.Hash(), Data: decryptedBinData, FromGate: 0}\n//\terr = queueTx.Create()\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Creating queue_tx\")\n//\t\treturn nil, utils.ErrInfo(err)\n//\t}\n//\n//\treturn &network.DisTrResponse{}, nil\n//}\n\n// DecryptData is decrypting data\nfunc DecryptData(binaryTx *[]byte) ([]byte, []byte, []byte, error) {\n\tif len(*binaryTx) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"binary tx is empty\")\n\t\treturn nil, nil, nil, utils.ErrInfo(\"len(binaryTx) == 0\")\n\t}\n\n\tmyUserID := converter.BinToDecBytesShift(&*binaryTx, 5)\n\tlog.WithFields(log.Fields{\"user_id\": myUserID}).Debug(\"decrypted userID is\")\n\n\t// remove the encrypted key, and all that stay in $binary_tx will be encrypted keys of the transactions/blocks\n\tlength, err := converter.DecodeLength(&*binaryTx)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ProtocolError, \"error\": err}).Error(\"Decoding binary tx length\")\n\t\treturn nil, nil, nil, err\n\t}\n\tencryptedKey := converter.BytesShift(&*binaryTx, length)\n\tiv := converter.BytesShift(&*binaryTx, 16)\n\tlog.WithFields(log.Fields{\"encryptedKey\": encryptedKey, \"iv\": iv}).Debug(\"binary tx encryptedKey and iv is\")\n\n\tif len(encryptedKey) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"binary tx encrypted key is empty\")\n\t\treturn nil, nil, nil, utils.ErrInfo(\"len(encryptedKey) == 0\")\n\t}\n\n\tif len(*binaryTx) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"binary tx is empty\")\n\t\treturn nil, nil, nil, utils.ErrInfo(\"len(*binaryTx) == 0\")\n\t}\n\n\tnodeKeyPrivate, _ := utils.GetNodeKeys()\n\tif len(nodeKeyPrivate) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node private key is empty\")\n\t\treturn nil, nil, nil, utils.ErrInfo(\"len(nodePrivateKey) == 0\")\n\t}\n\n\tblock, _ := pem.Decode([]byte(nodeKeyPrivate))\n\tif block == nil || block.Type != \"RSA PRIVATE KEY\" {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError}).Error(\"No valid PEM data found\")\n\t\treturn nil, nil, nil, utils.ErrInfo(\"No valid PEM data found\")\n\t}\n\n\tprivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"Parse PKCS1PrivateKey\")\n\t\treturn nil, nil, nil, utils.ErrInfo(err)\n\t}\n\n\tdecKey, err := rsa.DecryptPKCS1v15(crand.Reader, privateKey, encryptedKey)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"rsa Decrypt\")\n\t\treturn nil, nil, nil, utils.ErrInfo(err)\n\t}\n\n\tlog.WithFields(log.Fields{\"key\": decKey}).Debug(\"decrypted key\")\n\tif len(decKey) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"decrypted key is empty\")\n\t\treturn nil, nil, nil, utils.ErrInfo(\"len(decKey)\")\n\t}\n\n\tlog.WithFields(log.Fields{\"binaryTx\": *binaryTx, \"iv\": iv}).Debug(\"binaryTx and iv is\")\n\tdecrypted, err := aes.Decrypt(iv, *binaryTx, decKey)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"Decryption binary tx\")\n\t\treturn nil, nil, nil, utils.ErrInfo(err)\n\t}\n\n\treturn decKey, iv, decrypted, nil\n}\n\nfunc UnmarshalTxPacket(dat []byte) ([][]byte, error) {\n\tvar txes [][]byte\n\terr := json.Unmarshal(dat, &txes)\n\treturn txes, err\n}\n"
  },
  {
    "path": "packages/network/tcpserver/disseminator.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\n\t\"gorm.io/gorm/clause\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Disseminator get the list of transactions which belong to the sender from 'disseminator' daemon\n// do not load the blocks here because here could be the chain of blocks that are loaded for a long time\n// download the transactions here, because they are small and definitely will be downloaded in 60 sec\nfunc Disseminator(rw io.ReadWriter) error {\n\tr := &network.DisRequest{}\n\tif err := r.Read(rw); err != nil {\n\t\treturn err\n\t}\n\n\tbuf := bytes.NewBuffer(r.Data)\n\n\t/*\n\t *  data structure\n\t *  type - 1 byte. 0 - block, 1 - list of transactions\n\t *  {if type==1}:\n\t *  <any number of the next sets>\n\t *   tx_hash - 32 bytes\n\t * </>\n\t * {if type==0}:\n\t *  block_id - 3 bytes\n\t *  hash - 32 bytes\n\t * <any number of the next sets>\n\t *   tx_hash - 32 bytes\n\t * </>\n\t * */\n\n\t// honor_node_id of the sender to know where to take a data when it will be downloaded by another daemon\n\thonorNodeID := converter.BinToDec(buf.Next(8))\n\tlog.Debug(\"honorNodeID\", honorNodeID)\n\tn, err := syspar.GetNodeByPosition(honorNodeID)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on getting node by position\")\n\t\treturn err\n\t}\n\n\t// get data type (0 - block and transactions, 1 - only transactions)\n\tnewDataType := converter.BinToDec(buf.Next(1))\n\n\tlog.Debug(\"newDataType\", newDataType)\n\tif newDataType == 0 {\n\t\tbanned := n != nil && node.GetNodesBanService().IsBanned(*n)\n\t\tif banned {\n\t\t\tbuf.Next(3)\n\t\t\tbuf.Next(consts.HashSize)\n\t\t} else {\n\t\t\terr := processBlock(buf, honorNodeID)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithError(err).Error(\"on process block\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// get unknown transactions from received packet\n\tneedTx, err := getUnknownTransactions(buf)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on getting unknown txes\")\n\t\treturn err\n\t}\n\n\t// send the list of transactions which we want to get\n\terr = (&network.DisHashResponse{Data: needTx}).Write(rw)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on sending neeeded tx list\")\n\t\treturn err\n\t}\n\n\tif len(needTx) == 0 {\n\t\treturn nil\n\t}\n\n\t// get this new transactions\n\ttxBodies, err := resieveTxBodies(rw)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"on reading needed txes from disseminator\")\n\t\treturn err\n\t}\n\n\t// and save them\n\treturn saveNewTransactions(txBodies)\n}\n\nfunc resieveTxBodies(con io.Reader) ([]byte, error) {\n\tsizeBuf := make([]byte, 4)\n\tif _, err := io.ReadFull(con, sizeBuf); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on getting size of tx bodies\")\n\t\treturn nil, err\n\t}\n\n\tsize := converter.BinToDec(sizeBuf)\n\ttxBodies := make([]byte, size)\n\tif _, err := io.ReadFull(con, txBodies); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"on getting tx bodies\")\n\t\treturn nil, err\n\t}\n\n\treturn txBodies, nil\n}\n\nfunc processBlock(buf *bytes.Buffer, honorNodeID int64) error {\n\tinfoBlock := &sqldb.InfoBlock{}\n\tfound, err := infoBlock.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting cur block ID\")\n\t\treturn utils.ErrInfo(err)\n\t}\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound}).Error(\"cant find info block\")\n\t\treturn errors.New(\"can't find info block\")\n\t}\n\n\t// get block ID\n\tnewBlockID := converter.BinToDec(buf.Next(3))\n\tlog.WithFields(log.Fields{\"new_block_id\": newBlockID}).Debug(\"Generated new block id\")\n\n\t// get block hash\n\tblockHash := buf.Next(consts.HashSize)\n\tlog.Debugf(\"blockHash %x\", blockHash)\n\n\tqb := &sqldb.QueueBlock{}\n\tfound, err = qb.GetQueueBlockByHash(blockHash)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting QueueBlock\")\n\t\treturn utils.ErrInfo(err)\n\t}\n\t// we accept only new blocks\n\tif !found && newBlockID >= infoBlock.BlockID {\n\t\tqueueBlock := &sqldb.QueueBlock{Hash: blockHash, HonorNodeID: honorNodeID, BlockID: newBlockID}\n\t\terr = queueBlock.Create()\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Creating QueueBlock\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc getUnknownTransactions(buf *bytes.Buffer) ([]byte, error) {\n\thashes, err := readHashes(buf)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ProtocolError, \"error\": err}).Error(\"on reading hashes\")\n\t\treturn nil, err\n\t}\n\n\tvar needTx []byte\n\t// TODO: remove cycle, select miltiple txes throw in(?)\n\tfor _, hash := range hashes {\n\t\t// check if we have such a transaction\n\t\t// check log_transaction\n\t\texists, err := sqldb.GetLogTransactionsCount(hash)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"txHash\": hash}).Error(\"Getting log tx count\")\n\t\t\treturn nil, utils.ErrInfo(err)\n\t\t}\n\t\tif exists > 0 {\n\t\t\tlog.WithFields(log.Fields{\"txHash\": hash, \"type\": consts.DuplicateObject}).Warning(\"tx with this hash already exists in log_tx\")\n\t\t\tcontinue\n\t\t}\n\n\t\texists, err = sqldb.GetTransactionsCount(hash)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"txHash\": hash}).Error(\"Getting tx count\")\n\t\t\treturn nil, utils.ErrInfo(err)\n\t\t}\n\t\tif exists > 0 {\n\t\t\tlog.WithFields(log.Fields{\"txHash\": hash, \"type\": consts.DuplicateObject}).Warning(\"tx with this hash already exists in tx\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// check transaction queue\n\t\texists, err = sqldb.GetQueuedTransactionsCount(hash)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting queue_tx count\")\n\t\t\treturn nil, utils.ErrInfo(err)\n\t\t}\n\t\tif exists > 0 {\n\t\t\tlog.WithFields(log.Fields{\"txHash\": hash, \"type\": consts.DuplicateObject}).Warning(\"tx with this hash already exists in queue_tx\")\n\t\t\tcontinue\n\t\t}\n\t\tneedTx = append(needTx, hash...)\n\t}\n\n\treturn needTx, nil\n}\n\nfunc readHashes(buf *bytes.Buffer) ([][]byte, error) {\n\tif buf.Len()%consts.HashSize != 0 {\n\t\tlog.WithFields(log.Fields{\"hashes_slice_size\": buf.Len(), \"tx_size\": consts.HashSize, \"type\": consts.ProtocolError}).Error(\"incorrect hashes length\")\n\t\treturn nil, errors.New(\"wrong transactions hashes size\")\n\t}\n\n\thashes := make([][]byte, 0, buf.Len()/consts.HashSize)\n\n\tfor buf.Len() > 0 {\n\t\thashes = append(hashes, buf.Next(consts.HashSize))\n\t}\n\n\treturn hashes, nil\n}\n\nfunc saveNewTransactions(binaryTxs []byte) error {\n\tvar queueTxs []*sqldb.QueueTx\n\tlog.WithFields(log.Fields{\"binaryTxs\": binaryTxs}).Debug(\"trying to save binary txs\")\n\n\tfor len(binaryTxs) > 0 {\n\t\ttxSize, err := converter.DecodeLength(&binaryTxs)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ProtocolError, \"err\": err}).Error(\"decoding binary txs length\")\n\t\t\treturn err\n\t\t}\n\t\tif int64(len(binaryTxs)) < txSize {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ProtocolError, \"size\": txSize, \"len\": len(binaryTxs)}).Error(\"incorrect binary txs len\")\n\t\t\treturn utils.ErrInfo(errors.New(\"bad transactions packet\"))\n\t\t}\n\n\t\ttxBinData := converter.BytesShift(&binaryTxs, txSize)\n\t\tif len(txBinData) == 0 {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"binaryTxs is empty\")\n\t\t\treturn utils.ErrInfo(errors.New(\"len(txBinData) == 0\"))\n\t\t}\n\n\t\tif int64(len(txBinData)) > syspar.GetMaxTxSize() {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"len\": len(txBinData), \"size\": syspar.GetMaxTxSize()}).Error(\"len of tx data exceeds max size\")\n\t\t\treturn utils.ErrInfo(\"len(txBinData) > max_tx_size\")\n\t\t}\n\n\t\trtx := transaction.Transaction{}\n\t\tif err = rtx.Unmarshall(bytes.NewBuffer(txBinData), true); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err}).Error(\"unmarshalling transaction\")\n\t\t\treturn err\n\t\t}\n\t\tqueueTxs = append(queueTxs, &sqldb.QueueTx{Hash: rtx.Hash(), Data: txBinData, Expedite: rtx.Expedite(), Time: rtx.Timestamp(), FromGate: 1})\n\t}\n\tif err := sqldb.GetDB(nil).Clauses(clause.OnConflict{DoNothing: true}).Create(&queueTxs).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"error creating QueueTx\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/network/tcpserver/max_block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// MaxBlock sends the last block ID\n// blocksCollection daemon sends this request\nfunc MaxBlock() (*network.MaxBlockResponse, error) {\n\tinfoBlock := &sqldb.InfoBlock{}\n\tfound, err := infoBlock.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting cur blockID\")\n\t\treturn nil, utils.ErrInfo(err)\n\t}\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"Can't found info block\")\n\t}\n\n\treturn &network.MaxBlockResponse{\n\t\tBlockID: infoBlock.BlockID,\n\t}, nil\n}\n"
  },
  {
    "path": "packages/network/tcpserver/stop_network.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\n\t\"net\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/x509\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar errStopCertAlreadyUsed = errors.New(\"Stop certificate is already used\")\n\n// StopNetwork is stop network tx type\nfunc StopNetwork(req *network.StopNetworkRequest, w net.Conn) error {\n\thash, err := processStopNetwork(req.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tres := &network.StopNetworkResponse{hash}\n\tif err = res.Write(w); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.NetworkError}).Error(\"sending response\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc processStopNetwork(b []byte) ([]byte, error) {\n\tcert, err := x509.ParseCert(b)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.ParseError}).Error(\"parsing cert\")\n\t\treturn nil, err\n\t}\n\n\tif cert.EqualBytes(consts.UsedStopNetworkCerts...) {\n\t\tlog.WithFields(log.Fields{\"error\": errStopCertAlreadyUsed, \"type\": consts.InvalidObject}).Error(\"checking cert\")\n\t\treturn nil, errStopCertAlreadyUsed\n\t}\n\n\tfbdata, err := syspar.GetFirstBlockData()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.ConfigError}).Error(\"getting data of first block\")\n\t\treturn nil, err\n\t}\n\n\tif err = cert.Validate(fbdata.StopNetworkCertBundle); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.InvalidObject}).Error(\"validating cert\")\n\t\treturn nil, err\n\t}\n\n\tvar data []byte\n\tsnp := new(transaction.StopNetworkParser)\n\tdata, err = snp.BinMarshal(&types.StopNetwork{\n\t\tKeyID:           conf.Config.KeyID,\n\t\tTime:            time.Now().Unix(),\n\t\tStopNetworkCert: b,\n\t})\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.MarshallingError}).Error(\"binary marshaling\")\n\t\treturn nil, err\n\t}\n\n\thash := crypto.DoubleHash(data)\n\ttx := &sqldb.Transaction{\n\t\tHash:     hash,\n\t\tData:     data,\n\t\tType:     types.StopNetworkTxType,\n\t\tKeyID:    conf.Config.KeyID,\n\t\tHighRate: sqldb.TransactionRateStopNetwork,\n\t\tTime:     snp.Timestamp,\n\t}\n\tif err = tx.Create(nil); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"inserting tx to database\")\n\t\treturn nil, err\n\t}\n\n\treturn hash, nil\n}\n"
  },
  {
    "path": "packages/network/tcpserver/tcpserver.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage tcpserver\n\nimport (\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// HandleTCPRequest proceed TCP requests\nfunc HandleTCPRequest(rw net.Conn) {\n\tdType := &network.RequestType{}\n\terr := dType.Read(rw)\n\tif err != nil {\n\t\tlog.Errorf(\"read request type failed: %s\", err)\n\t\treturn\n\t}\n\n\tlog.WithFields(log.Fields{\"request_type\": dType.Type}).Debug(\"tcpserver got request type\")\n\tvar response network.SelfReaderWriter\n\n\tswitch dType.Type {\n\tcase network.RequestTypeHonorNode:\n\t\tif node.IsNodePaused() {\n\t\t\treturn\n\t\t}\n\t\terr = Disseminator(rw)\n\n\tcase network.RequestTypeNotHonorNode:\n\t\tif node.IsNodePaused() {\n\t\t\treturn\n\t\t}\n\t\terr = DisseminateTxs(rw)\n\n\tcase network.RequestTypeStopNetwork:\n\t\treq := &network.StopNetworkRequest{}\n\t\tif err = req.Read(rw); err == nil {\n\t\t\terr = StopNetwork(req, rw)\n\t\t}\n\n\tcase network.RequestTypeConfirmation:\n\t\t//if node.IsNodePaused() {\n\t\t//\treturn\n\t\t//}\n\n\t\treq := &network.ConfirmRequest{}\n\t\tif err = req.Read(rw); err == nil {\n\t\t\tresponse, err = Confirmation(req)\n\t\t}\n\n\tcase network.RequestTypeBlockCollection:\n\t\treq := &network.GetBodiesRequest{}\n\t\tif err = req.Read(rw); err == nil {\n\t\t\terr = BlockCollection(req, rw)\n\t\t}\n\n\tcase network.RequestTypeMaxBlock:\n\t\tresponse, err = MaxBlock()\n\n\tcase network.RequestTypeVoting:\n\t\treq := &network.CandidateNodeVotingRequest{}\n\t\tif err = req.Read(rw); err == nil {\n\t\t\tresponse, err = CandidateNodeVoting(req)\n\t\t}\n\tcase network.RequestSyncMatchineState:\n\t\treq := &network.BroadcastNodeConnInfoRequest{}\n\t\tif err = req.Read(rw); err == nil {\n\t\t\t_, err = SyncMatchineStateRes(req)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": \"SyncMatchineStateRes\", \"error\": err}).Error(\"SyncMatchineStateRes hour candidate voting\")\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\n\tif err != nil || response == nil {\n\t\treturn\n\t}\n\n\tlog.WithFields(log.Fields{\"response\": response, \"request_type\": dType.Type}).Debug(\"tcpserver responded\")\n\tif err = response.Write(rw); err != nil {\n\t\t// err = SendRequest(response, rw)\n\t\tlog.Errorf(\"tcpserver handle error: %s\", err)\n\t}\n}\n\n// TcpListener is listening tcp address\nfunc TcpListener(laddr string) error {\n\n\tif strings.HasPrefix(laddr, \"127.\") {\n\t\tlog.Warn(\"Listening at local address: \", laddr)\n\t}\n\n\tl, err := net.Listen(\"tcp\", laddr)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConnectionError, \"error\": err, \"host\": laddr}).Error(\"Error listening\")\n\t\treturn err\n\t}\n\n\tgo func() {\n\t\tdefer l.Close()\n\t\tfor {\n\t\t\tconn, err := l.Accept()\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConnectionError, \"error\": err, \"host\": laddr}).Error(\"Error accepting\")\n\t\t\t\ttime.Sleep(time.Second)\n\t\t\t} else {\n\t\t\t\tgo func(conn net.Conn) {\n\t\t\t\t\tHandleTCPRequest(conn)\n\t\t\t\t\tconn.Close()\n\t\t\t\t}(conn)\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/notificator/notificator.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage notificator\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/publisher\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype notificationRecord struct {\n\tEcosystemID  string `json:\"ecosystem\"`\n\tRoleID       string `json:\"role_id\"`\n\tRecordsCount int64  `json:\"count\"`\n}\n\n// UpdateNotifications send stats about unreaded messages to centrifugo for ecosystem\nfunc UpdateNotifications(ecosystemID int64, accounts []string) {\n\tnotificationsStats, err := getEcosystemNotificationStats(ecosystemID, accounts)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tfor account, n := range notificationsStats {\n\t\tsendUserStats(account, *n)\n\t}\n}\n\n// UpdateRolesNotifications send stats about unreaded messages to centrifugo for ecosystem\nfunc UpdateRolesNotifications(ecosystemID int64, roles []int64) {\n\tmembers, _ := sqldb.GetRoleMembers(nil, ecosystemID, roles)\n\tUpdateNotifications(ecosystemID, members)\n}\n\nfunc getEcosystemNotificationStats(ecosystemID int64, users []string) (map[string]*[]notificationRecord, error) {\n\tresult, err := sqldb.GetNotificationsCount(ecosystemID, users)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting notification count\")\n\t\treturn nil, err\n\t}\n\n\treturn parseRecipientNotification(result, ecosystemID), nil\n}\n\nfunc parseRecipientNotification(rows []sqldb.NotificationsCount, systemID int64) map[string]*[]notificationRecord {\n\trecipientNotifications := make(map[string]*[]notificationRecord)\n\n\tfor _, r := range rows {\n\t\tif r.RecipientID == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\troleNotifications := notificationRecord{\n\t\t\tEcosystemID:  converter.Int64ToStr(systemID),\n\t\t\tRoleID:       converter.Int64ToStr(r.RoleID),\n\t\t\tRecordsCount: r.Count,\n\t\t}\n\n\t\tnr, ok := recipientNotifications[r.Account]\n\t\tif ok {\n\t\t\t*nr = append(*nr, roleNotifications)\n\t\t\tcontinue\n\t\t}\n\n\t\trecords := []notificationRecord{\n\t\t\troleNotifications,\n\t\t}\n\n\t\trecipientNotifications[r.Account] = &records\n\t}\n\n\treturn recipientNotifications\n}\n\nfunc sendUserStats(account string, stats []notificationRecord) {\n\trawStats, err := json.Marshal(stats)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"notification statistic\")\n\t}\n\n\terr = publisher.Write(account, string(rawStats))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Debug(\"writing to centrifugo\")\n\t}\n}\n"
  },
  {
    "path": "packages/notificator/queue.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage notificator\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\ntype Queue struct {\n\tAccounts []*Accounts\n\tRoles    []*Roles\n}\n\ntype Accounts struct {\n\tEcosystem int64\n\tList      []string\n}\n\ntype Roles struct {\n\tEcosystem int64\n\tList      []int64\n}\n\nfunc (q *Queue) Size() int {\n\treturn len(q.Accounts) + len(q.Roles)\n}\n\nfunc (q *Queue) AddAccounts(ecosystem int64, list ...string) {\n\tq.Accounts = append(q.Accounts, &Accounts{\n\t\tEcosystem: ecosystem,\n\t\tList:      list,\n\t})\n}\n\nfunc (q *Queue) AddRoles(ecosystem int64, list ...int64) {\n\tq.Roles = append(q.Roles, &Roles{\n\t\tEcosystem: ecosystem,\n\t\tList:      list,\n\t})\n}\n\nfunc (q *Queue) Send() {\n\tfor _, a := range q.Accounts {\n\t\tUpdateNotifications(a.Ecosystem, a.List)\n\t}\n\n\tfor _, r := range q.Roles {\n\t\tUpdateRolesNotifications(r.Ecosystem, r.List)\n\t}\n}\n\nfunc NewQueue() types.Notifications {\n\treturn &Queue{\n\t\tAccounts: make([]*Accounts, 0),\n\t\tRoles:    make([]*Roles, 0),\n\t}\n}\n"
  },
  {
    "path": "packages/notificator/token_movements.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage notificator\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/shopspring/decimal\"\n\n\t\"net/smtp\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tnetworkPerDayLimit            = 100000000\n\tnetworkPerDayMsgTemplate      = \"day chain movement volume =  %s\"\n\tfromToDayLimitMsgTemplate     = \"from %d to %d sended volume = %s\"\n\tperBlockTokenMovementTemplate = \"from wallet %d token movement count = %d in block: %d\"\n\n\tnetworkPerDayEvent         = 1\n\tfromToDayLimitEvent        = 2\n\tperBlockTokenMovementEvent = 3\n)\n\nvar lastLimitEvents map[uint8]time.Time\n\nfunc init() {\n\tlastLimitEvents = make(map[uint8]time.Time, 0)\n}\n\nfunc sendEmail(conf conf.TokenMovementConfig, message string) error {\n\tauth := smtp.PlainAuth(\"\", conf.Username, conf.Password, conf.Host)\n\tto := []string{conf.To}\n\tmsg := []byte(fmt.Sprintf(\"From: %s\\r\\n\", conf.From) +\n\t\tfmt.Sprintf(\"To: %s\\r\\n\", conf.To) +\n\t\tfmt.Sprintf(\"Subject: %s\\r\\n\", conf.Subject) +\n\t\t\"\\r\\n\" +\n\t\tfmt.Sprintf(\"%s\\r\\n\", message))\n\terr := smtp.SendMail(fmt.Sprintf(\"%s:%d\", conf.Host, conf.Port), auth, conf.From, to, msg)\n\tif err != nil {\n\t\tlog.WithError(err).Error(\"sending email\")\n\t}\n\treturn err\n}\n\n// CheckTokenMovementLimits check all limits\nfunc CheckTokenMovementLimits(tx *sqldb.DbTransaction, conf conf.TokenMovementConfig, blockID int64) {\n\tvar messages []string\n\tif needCheck(networkPerDayEvent) {\n\t\tamount, err := sqldb.GetExcessCommonTokenMovementPerDay(tx)\n\n\t\tif err != nil {\n\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"check common token movement\")\n\t\t} else if amount.GreaterThanOrEqual(decimal.NewFromFloat(networkPerDayLimit)) {\n\n\t\t\tmessages = append(messages, fmt.Sprintf(networkPerDayMsgTemplate, amount.String()))\n\t\t\tlastLimitEvents[networkPerDayEvent] = time.Now()\n\t\t}\n\t}\n\n\tif needCheck(fromToDayLimitEvent) {\n\t\ttransfers, err := sqldb.GetExcessFromToTokenMovementPerDay(tx)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"check from to token movement\")\n\t\t} else {\n\t\t\tfor _, transfer := range transfers {\n\t\t\t\tmessages = append(messages, fmt.Sprintf(fromToDayLimitMsgTemplate, transfer.SenderID, transfer.RecipientID, transfer.Amount))\n\t\t\t}\n\n\t\t\tif len(transfers) > 0 {\n\t\t\t\tlastLimitEvents[fromToDayLimitEvent] = time.Now()\n\t\t\t}\n\t\t}\n\t}\n\n\texcesses, err := sqldb.GetExcessTokenMovementQtyPerBlock(tx, blockID)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"check token movement per block\")\n\t} else {\n\t\tfor _, excess := range excesses {\n\t\t\tmessages = append(messages, fmt.Sprintf(perBlockTokenMovementTemplate, excess.SenderID, excess.TxCount, blockID))\n\t\t}\n\t}\n\n\tif len(messages) > 0 {\n\t\tsendEmail(conf, strings.Join(messages, \"\\n\"))\n\t}\n}\n\n// checks needed only if we have'nt prevent events or if event older then 1 day\nfunc needCheck(event uint8) bool {\n\tt, ok := lastLimitEvents[event]\n\tif !ok {\n\t\treturn true\n\t}\n\n\treturn time.Now().Sub(t) >= 24*time.Hour\n}\n"
  },
  {
    "path": "packages/pb/Makefile",
    "content": "\n# install tools\npb-install:\n\tgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest\n\tgo install github.com/golang/protobuf/protoc-gen-go@latest\n\tgo get -u google.golang.org/grpc\n\tgo install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway@latest\n\tgo install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger@latest\n\tgo install github.com/gogo/protobuf/protoc-gen-gogofaster@latest\n\n# generate *.pb.go file\npb-generate:\n\tprotoc -I=. --gogofaster_out=:../script --gogofaster_opt=paths=source_relative ./vm.proto\n\tprotoc -I=. --gogofaster_out=:../smart --gogofaster_opt=paths=source_relative ./gas.proto\n\tprotoc -I=. --gogofaster_out=:../types --gogofaster_opt=paths=source_relative ./block.proto\n\tprotoc -I=.  --gogofaster_out=:../pbgo --gogofaster_opt=paths=source_relative ./tx.proto\n\tprotoc -I=.  --gogofaster_out=:../common/crypto --gogofaster_opt=paths=source_relative ./crypto.proto\n\tprotoc -I=.  --gogofaster_out=:../types --gogofaster_opt=paths=source_relative ./play.proto\n\n"
  },
  {
    "path": "packages/pb/block.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/IBAX-io/go-ibax/packages/types\";\n\npackage types;\n\nimport \"play.proto\";\n\n// BlockSyncMethod define block sync method.\nenum BlockSyncMethod{\n  CONTRACTVM = 0;\n  SQLDML = 1;\n}\n\n//BlockHeader is a structure of the block's header\nmessage BlockHeader{\n  int64 block_id = 1;\n  int64 timestamp = 2;\n  int64 ecosystem_id = 3;\n  int64 key_id = 4;\n  int64 node_position = 5;\n  bytes sign = 6;\n  bytes block_hash = 7;\n  //differences with before and after in tx modification table\n  bytes rollbacks_hash = 8;\n  int32 version = 9;\n  int32 consensus_mode = 10;\n  bytes candidate_nodes = 11;\n  int64 network_id = 12;\n}\n\n// BlockData is a structure of the block's\nmessage BlockData {\n    BlockHeader header = 1;\n    BlockHeader prev_header = 2;\n    bytes merkle_root =3;\n    bytes bin_data =4;\n    repeated bytes tx_full_data =5;\n    AfterTxs after_txs =6;\n    bool sys_update = 7;\n}\n"
  },
  {
    "path": "packages/pb/crypto.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/IBAX-io/go-ibax/packages/common/crypto\";\n\npackage crypto;\n\n// AsymAlgo is asymmetric algorithms\nenum AsymAlgo{\n  ECC_P256 = 0;\n  ECC_Secp256k1 = 1;\n  SM2 = 2;\n  ECC_P512 = 3;\n}\n\n// SymAlgo is symmetric algorithms\nenum SymAlgo{\n  AES = 0;\n  SM4 = 1;\n}\n\n// HashAlgo is hash algorithms\nenum HashAlgo{\n  SHA256 = 0;\n  KECCAK256 = 1;\n  SM3 = 2;\n  SHA3_256 = 3;\n}\n\n\n"
  },
  {
    "path": "packages/pb/gas.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/IBAX-io/go-ibax/packages/smart\";\n\npackage smart;\n\nenum PaymentType {\n  INVALID = 0;\n  ContractCaller = 1;\n  ContractBinder = 2;\n  EcosystemAddress = 3;\n}\n\nenum GasScenesType {\n  Unknown = 0;\n  Reward = 1;\n  Taxes = 2;\n  Direct = 15;\n  Combustion = 16;\n  TransferSelf =  24;\n}\n\nenum GasPayAbleType {\n  Invalid = 0;\n  Unable = 1;\n  Capable = 2;\n}\n\nenum FuelType {\n  UNKNOWN = 0;\n  vmCost_fee = 1;\n  storage_fee = 2;\n  expedite_fee = 3;\n}\nenum Arithmetic {\n  NATIVE = 0;\n  MUL = 3;\n  DIV = 4;\n}"
  },
  {
    "path": "packages/pb/play.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/IBAX-io/go-ibax/packages/types\";\n\npackage types;\n\nimport \"tx.proto\";\n\n//AfterTxs defined block batch process tx for sql DML\nmessage AfterTxs {\n  repeated AfterTx txs =1;\n  //TxBinLogSql defined contract exec sql for tx DML\n//  repeated bytes tx_bin_log_sql = 2;\n  repeated     RollbackTx rts = 3;\n}\n\nmessage AfterTx {\n    bytes used_tx = 1;\n    LogTransaction lts = 2;\n    pbgo.TxResult upd_tx_status = 3;\n}\n\nmessage RollbackTx {\n  int64 id = 1;\n  int64 block_id = 2;\n  bytes tx_hash = 3;\n  string name_table = 4;\n  string table_id = 5;\n  string data = 6;\n  bytes data_hash = 7;\n}\n\nmessage LogTransaction {\n  bytes hash = 1;\n  int64 block = 2;\n//  bytes tx_data = 3;\n  int64 timestamp = 4;\n  int64 address = 5;\n  int64 ecosystem_id = 6;\n  string contract_name = 7;\n  pbgo.TxInvokeStatusCode invoke_status = 8;\n}\n"
  },
  {
    "path": "packages/pb/tx.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/IBAX-io/go-ibax/packages/pbgo\";\n\npackage pbgo;\n\n// Transaction types.\nenum TransactionTypes{\n  SMARTCONTRACT = 0;\n  FIRSTBLOCK = 1;\n  STOPNETWORK = 2;\n}\n\n// Transaction invoke status code.\nenum TxInvokeStatusCode{\n  SUCCESS = 0;\n  PENALTY = 1;\n  FAILED = 2;\n  PENDING = 3;\n}\n\nmessage FirstBlock {\n  int64 key_id = 1;\n  int64 timestamp = 2;\n  bytes public_key = 3;\n  bytes node_public_key = 4;\n  bytes stop_network_cert_bundle = 5;\n  int64 test = 6;\n  uint64 private_blockchain = 7;\n}\n\nmessage StopNetwork {\n  int64 key_id = 1;\n  int64 timestamp = 2;\n  bytes stop_network_cert = 3;\n}\n\nmessage TxResult{\n  bytes hash = 1;\n  int64 block_id = 2;\n  TxInvokeStatusCode code = 3;\n  string result = 4;\n  string error = 5;\n}"
  },
  {
    "path": "packages/pb/vm.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/IBAX-io/go-ibax/packages/script\";\n\npackage script;\n\n// VMType is virtual machine type\nenum VMType {\n  // VMType_INVALID is invalid type\n  INVALID = 0;\n  // VMType_Smart is smart vm type\n  Smart = 1;\n  // VMType_CLB is clb vm type\n  CLB = 2;\n  // VMType_CLBMaster is CLBMaster type\n  CLBMaster = 3;\n}\n\n// ObjectType Types of the compiled objects\nenum ObjectType{\n  // ObjUnknown is an unknown object.\n  Unknown = 0;\n  // ObjectType_Contract is a contract object.\n  Contract = 1;\n  // ObjectType_Func is a function object. myfunc()\n  Func = 2;\n  // ObjectType_ExtFunc is an extended build in function object. $myfunc()\n  ExtFunc = 3;\n  // ObjectType_Var is a variable. myvar\n  Var = 4;\n  // ObjectType_ExtVar is an extended build in variable. $myvar\n  ExtVar = 5;\n}"
  },
  {
    "path": "packages/pbgo/tx.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: tx.proto\n\npackage pbgo\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/gogo/protobuf/proto\"\n\tio \"io\"\n\tmath \"math\"\n\tmath_bits \"math/bits\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package\n\n// Transaction types.\ntype TransactionTypes int32\n\nconst (\n\tTransactionTypes_SMARTCONTRACT TransactionTypes = 0\n\tTransactionTypes_FIRSTBLOCK    TransactionTypes = 1\n\tTransactionTypes_STOPNETWORK   TransactionTypes = 2\n)\n\nvar TransactionTypes_name = map[int32]string{\n\t0: \"SMARTCONTRACT\",\n\t1: \"FIRSTBLOCK\",\n\t2: \"STOPNETWORK\",\n}\n\nvar TransactionTypes_value = map[string]int32{\n\t\"SMARTCONTRACT\": 0,\n\t\"FIRSTBLOCK\":    1,\n\t\"STOPNETWORK\":   2,\n}\n\nfunc (x TransactionTypes) String() string {\n\treturn proto.EnumName(TransactionTypes_name, int32(x))\n}\n\nfunc (TransactionTypes) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_0fd2153dc07d3b5c, []int{0}\n}\n\n// Transaction invoke status code.\ntype TxInvokeStatusCode int32\n\nconst (\n\tTxInvokeStatusCode_SUCCESS TxInvokeStatusCode = 0\n\tTxInvokeStatusCode_PENALTY TxInvokeStatusCode = 1\n\tTxInvokeStatusCode_FAILED  TxInvokeStatusCode = 2\n\tTxInvokeStatusCode_PENDING TxInvokeStatusCode = 3\n)\n\nvar TxInvokeStatusCode_name = map[int32]string{\n\t0: \"SUCCESS\",\n\t1: \"PENALTY\",\n\t2: \"FAILED\",\n\t3: \"PENDING\",\n}\n\nvar TxInvokeStatusCode_value = map[string]int32{\n\t\"SUCCESS\": 0,\n\t\"PENALTY\": 1,\n\t\"FAILED\":  2,\n\t\"PENDING\": 3,\n}\n\nfunc (x TxInvokeStatusCode) String() string {\n\treturn proto.EnumName(TxInvokeStatusCode_name, int32(x))\n}\n\nfunc (TxInvokeStatusCode) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_0fd2153dc07d3b5c, []int{1}\n}\n\ntype FirstBlock struct {\n\tKeyId                 int64  `protobuf:\"varint,1,opt,name=key_id,json=keyId,proto3\" json:\"key_id,omitempty\"`\n\tTimestamp             int64  `protobuf:\"varint,2,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\tPublicKey             []byte `protobuf:\"bytes,3,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tNodePublicKey         []byte `protobuf:\"bytes,4,opt,name=node_public_key,json=nodePublicKey,proto3\" json:\"node_public_key,omitempty\"`\n\tStopNetworkCertBundle []byte `protobuf:\"bytes,5,opt,name=stop_network_cert_bundle,json=stopNetworkCertBundle,proto3\" json:\"stop_network_cert_bundle,omitempty\"`\n\tTest                  int64  `protobuf:\"varint,6,opt,name=test,proto3\" json:\"test,omitempty\"`\n\tPrivateBlockchain     uint64 `protobuf:\"varint,7,opt,name=private_blockchain,json=privateBlockchain,proto3\" json:\"private_blockchain,omitempty\"`\n}\n\nfunc (m *FirstBlock) Reset()         { *m = FirstBlock{} }\nfunc (m *FirstBlock) String() string { return proto.CompactTextString(m) }\nfunc (*FirstBlock) ProtoMessage()    {}\nfunc (*FirstBlock) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_0fd2153dc07d3b5c, []int{0}\n}\nfunc (m *FirstBlock) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *FirstBlock) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_FirstBlock.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *FirstBlock) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_FirstBlock.Merge(m, src)\n}\nfunc (m *FirstBlock) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *FirstBlock) XXX_DiscardUnknown() {\n\txxx_messageInfo_FirstBlock.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_FirstBlock proto.InternalMessageInfo\n\nfunc (m *FirstBlock) GetKeyId() int64 {\n\tif m != nil {\n\t\treturn m.KeyId\n\t}\n\treturn 0\n}\n\nfunc (m *FirstBlock) GetTimestamp() int64 {\n\tif m != nil {\n\t\treturn m.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (m *FirstBlock) GetPublicKey() []byte {\n\tif m != nil {\n\t\treturn m.PublicKey\n\t}\n\treturn nil\n}\n\nfunc (m *FirstBlock) GetNodePublicKey() []byte {\n\tif m != nil {\n\t\treturn m.NodePublicKey\n\t}\n\treturn nil\n}\n\nfunc (m *FirstBlock) GetStopNetworkCertBundle() []byte {\n\tif m != nil {\n\t\treturn m.StopNetworkCertBundle\n\t}\n\treturn nil\n}\n\nfunc (m *FirstBlock) GetTest() int64 {\n\tif m != nil {\n\t\treturn m.Test\n\t}\n\treturn 0\n}\n\nfunc (m *FirstBlock) GetPrivateBlockchain() uint64 {\n\tif m != nil {\n\t\treturn m.PrivateBlockchain\n\t}\n\treturn 0\n}\n\ntype StopNetwork struct {\n\tKeyId           int64  `protobuf:\"varint,1,opt,name=key_id,json=keyId,proto3\" json:\"key_id,omitempty\"`\n\tTimestamp       int64  `protobuf:\"varint,2,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\tStopNetworkCert []byte `protobuf:\"bytes,3,opt,name=stop_network_cert,json=stopNetworkCert,proto3\" json:\"stop_network_cert,omitempty\"`\n}\n\nfunc (m *StopNetwork) Reset()         { *m = StopNetwork{} }\nfunc (m *StopNetwork) String() string { return proto.CompactTextString(m) }\nfunc (*StopNetwork) ProtoMessage()    {}\nfunc (*StopNetwork) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_0fd2153dc07d3b5c, []int{1}\n}\nfunc (m *StopNetwork) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *StopNetwork) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_StopNetwork.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *StopNetwork) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_StopNetwork.Merge(m, src)\n}\nfunc (m *StopNetwork) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *StopNetwork) XXX_DiscardUnknown() {\n\txxx_messageInfo_StopNetwork.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_StopNetwork proto.InternalMessageInfo\n\nfunc (m *StopNetwork) GetKeyId() int64 {\n\tif m != nil {\n\t\treturn m.KeyId\n\t}\n\treturn 0\n}\n\nfunc (m *StopNetwork) GetTimestamp() int64 {\n\tif m != nil {\n\t\treturn m.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (m *StopNetwork) GetStopNetworkCert() []byte {\n\tif m != nil {\n\t\treturn m.StopNetworkCert\n\t}\n\treturn nil\n}\n\ntype TxResult struct {\n\tHash    []byte             `protobuf:\"bytes,1,opt,name=hash,proto3\" json:\"hash,omitempty\"`\n\tBlockId int64              `protobuf:\"varint,2,opt,name=block_id,json=blockId,proto3\" json:\"block_id,omitempty\"`\n\tCode    TxInvokeStatusCode `protobuf:\"varint,3,opt,name=code,proto3,enum=pbgo.TxInvokeStatusCode\" json:\"code,omitempty\"`\n\tResult  string             `protobuf:\"bytes,4,opt,name=result,proto3\" json:\"result,omitempty\"`\n\tError   string             `protobuf:\"bytes,5,opt,name=error,proto3\" json:\"error,omitempty\"`\n}\n\nfunc (m *TxResult) Reset()         { *m = TxResult{} }\nfunc (m *TxResult) String() string { return proto.CompactTextString(m) }\nfunc (*TxResult) ProtoMessage()    {}\nfunc (*TxResult) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_0fd2153dc07d3b5c, []int{2}\n}\nfunc (m *TxResult) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *TxResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_TxResult.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *TxResult) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_TxResult.Merge(m, src)\n}\nfunc (m *TxResult) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *TxResult) XXX_DiscardUnknown() {\n\txxx_messageInfo_TxResult.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_TxResult proto.InternalMessageInfo\n\nfunc (m *TxResult) GetHash() []byte {\n\tif m != nil {\n\t\treturn m.Hash\n\t}\n\treturn nil\n}\n\nfunc (m *TxResult) GetBlockId() int64 {\n\tif m != nil {\n\t\treturn m.BlockId\n\t}\n\treturn 0\n}\n\nfunc (m *TxResult) GetCode() TxInvokeStatusCode {\n\tif m != nil {\n\t\treturn m.Code\n\t}\n\treturn TxInvokeStatusCode_SUCCESS\n}\n\nfunc (m *TxResult) GetResult() string {\n\tif m != nil {\n\t\treturn m.Result\n\t}\n\treturn \"\"\n}\n\nfunc (m *TxResult) GetError() string {\n\tif m != nil {\n\t\treturn m.Error\n\t}\n\treturn \"\"\n}\n\nfunc init() {\n\tproto.RegisterEnum(\"pbgo.TransactionTypes\", TransactionTypes_name, TransactionTypes_value)\n\tproto.RegisterEnum(\"pbgo.TxInvokeStatusCode\", TxInvokeStatusCode_name, TxInvokeStatusCode_value)\n\tproto.RegisterType((*FirstBlock)(nil), \"pbgo.FirstBlock\")\n\tproto.RegisterType((*StopNetwork)(nil), \"pbgo.StopNetwork\")\n\tproto.RegisterType((*TxResult)(nil), \"pbgo.TxResult\")\n}\n\nfunc init() { proto.RegisterFile(\"tx.proto\", fileDescriptor_0fd2153dc07d3b5c) }\n\nvar fileDescriptor_0fd2153dc07d3b5c = []byte{\n\t// 516 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0xcd, 0x8e, 0xda, 0x3c,\n\t0x14, 0x25, 0xfc, 0x73, 0x99, 0x19, 0x82, 0xf5, 0xcd, 0xa7, 0x54, 0x6a, 0x23, 0xc4, 0xa2, 0x42,\n\t0xa8, 0x80, 0xd4, 0x2e, 0xba, 0x26, 0x19, 0x18, 0x45, 0x50, 0x40, 0x8e, 0xab, 0xfe, 0x6c, 0xa2,\n\t0xfc, 0x58, 0x10, 0x05, 0xe2, 0xc8, 0x31, 0x53, 0xd8, 0xf7, 0x01, 0xba, 0xe9, 0x3b, 0x75, 0x39,\n\t0xcb, 0x2e, 0x2b, 0x78, 0x91, 0x2a, 0x06, 0xcd, 0x54, 0x9d, 0x5d, 0x77, 0xf7, 0xdc, 0x73, 0x7c,\n\t0xef, 0xf1, 0xb1, 0xa1, 0x2a, 0x76, 0xfd, 0x84, 0x33, 0xc1, 0x50, 0x31, 0xf1, 0x96, 0xac, 0xfd,\n\t0x35, 0x0f, 0x30, 0x0e, 0x79, 0x2a, 0x8c, 0x35, 0xf3, 0x23, 0x74, 0x0d, 0xe5, 0x88, 0xee, 0x9d,\n\t0x30, 0xd0, 0x94, 0x96, 0xd2, 0x29, 0xe0, 0x52, 0x44, 0xf7, 0x56, 0x80, 0x9e, 0x43, 0x4d, 0x84,\n\t0x1b, 0x9a, 0x0a, 0x77, 0x93, 0x68, 0x79, 0xc9, 0x3c, 0x36, 0xd0, 0x0b, 0x80, 0x64, 0xeb, 0xad,\n\t0x43, 0xdf, 0x89, 0xe8, 0x5e, 0x2b, 0xb4, 0x94, 0xce, 0x05, 0xae, 0x9d, 0x3a, 0x13, 0xba, 0x47,\n\t0x2f, 0xa1, 0x11, 0xb3, 0x80, 0x3a, 0x7f, 0x68, 0x8a, 0x52, 0x73, 0x99, 0xb5, 0x17, 0x0f, 0xba,\n\t0xb7, 0xa0, 0xa5, 0x82, 0x25, 0x4e, 0x4c, 0xc5, 0x17, 0xc6, 0x23, 0xc7, 0xa7, 0x5c, 0x38, 0xde,\n\t0x36, 0x0e, 0xd6, 0x54, 0x2b, 0xc9, 0x03, 0xd7, 0x19, 0x3f, 0x3b, 0xd1, 0x26, 0xe5, 0xc2, 0x90,\n\t0x24, 0x42, 0x50, 0x14, 0x34, 0x15, 0x5a, 0x59, 0x1a, 0x93, 0x35, 0xea, 0x01, 0x4a, 0x78, 0x78,\n\t0xe7, 0x0a, 0xea, 0x78, 0xd9, 0xcd, 0xfc, 0x95, 0x1b, 0xc6, 0x5a, 0xa5, 0xa5, 0x74, 0x8a, 0xb8,\n\t0x79, 0x66, 0x8c, 0x07, 0xa2, 0x1d, 0x43, 0xdd, 0x7e, 0x9c, 0xfd, 0x6f, 0x31, 0x74, 0xa1, 0xf9,\n\t0xc4, 0xff, 0x39, 0x8d, 0xc6, 0x5f, 0xc6, 0xdb, 0xdf, 0x15, 0xa8, 0x92, 0x1d, 0xa6, 0xe9, 0x76,\n\t0x2d, 0x32, 0xff, 0x2b, 0x37, 0x5d, 0xc9, 0x5d, 0x17, 0x58, 0xd6, 0xe8, 0x19, 0x54, 0xa5, 0xef,\n\t0xcc, 0xc3, 0x69, 0x53, 0x45, 0x62, 0x2b, 0x40, 0xaf, 0xa0, 0xe8, 0xb3, 0x80, 0xca, 0xd1, 0x57,\n\t0xaf, 0xb5, 0x7e, 0xf6, 0x8e, 0x7d, 0xb2, 0xb3, 0xe2, 0x3b, 0x16, 0x51, 0x5b, 0xb8, 0x62, 0x9b,\n\t0x9a, 0x2c, 0xa0, 0x58, 0xaa, 0xd0, 0xff, 0x50, 0xe6, 0x72, 0x8d, 0x0c, 0xbd, 0x86, 0xcf, 0x08,\n\t0xfd, 0x07, 0x25, 0xca, 0x39, 0xe3, 0x32, 0xda, 0x1a, 0x3e, 0x81, 0xee, 0x18, 0x54, 0xc2, 0xdd,\n\t0x38, 0x75, 0x7d, 0x11, 0xb2, 0x98, 0xec, 0x13, 0x9a, 0xa2, 0x26, 0x5c, 0xda, 0xef, 0x86, 0x98,\n\t0x98, 0xf3, 0x19, 0xc1, 0x43, 0x93, 0xa8, 0x39, 0x74, 0x05, 0x30, 0xb6, 0xb0, 0x4d, 0x8c, 0xe9,\n\t0xdc, 0x9c, 0xa8, 0x0a, 0x6a, 0x40, 0xdd, 0x26, 0xf3, 0xc5, 0x6c, 0x44, 0x3e, 0xcc, 0xf1, 0x44,\n\t0xcd, 0x77, 0x6f, 0x01, 0x3d, 0x75, 0x84, 0xea, 0x50, 0xb1, 0xdf, 0x9b, 0xe6, 0xc8, 0xb6, 0xd5,\n\t0x5c, 0x06, 0x16, 0xa3, 0xd9, 0x70, 0x4a, 0x3e, 0xa9, 0x0a, 0x02, 0x28, 0x8f, 0x87, 0xd6, 0x74,\n\t0x74, 0xa3, 0xe6, 0xcf, 0xc4, 0x8d, 0x35, 0xbb, 0x55, 0x0b, 0x86, 0xf1, 0xe3, 0xa0, 0x2b, 0xf7,\n\t0x07, 0x5d, 0xf9, 0x75, 0xd0, 0x95, 0x6f, 0x47, 0x3d, 0x77, 0x7f, 0xd4, 0x73, 0x3f, 0x8f, 0x7a,\n\t0xee, 0x73, 0x67, 0x19, 0x8a, 0xd5, 0xd6, 0xeb, 0xfb, 0x6c, 0x33, 0xb0, 0x8c, 0xe1, 0xc7, 0x5e,\n\t0xc8, 0x06, 0x4b, 0xd6, 0x0b, 0x3d, 0x77, 0x37, 0x48, 0x5c, 0x3f, 0x72, 0x97, 0x34, 0x1d, 0x64,\n\t0xd9, 0x78, 0x65, 0xf9, 0xe1, 0xdf, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x00, 0xe8, 0x53, 0x93,\n\t0xfc, 0x02, 0x00, 0x00,\n}\n\nfunc (m *FirstBlock) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *FirstBlock) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *FirstBlock) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.PrivateBlockchain != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.PrivateBlockchain))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Test != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.Test))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.StopNetworkCertBundle) > 0 {\n\t\ti -= len(m.StopNetworkCertBundle)\n\t\tcopy(dAtA[i:], m.StopNetworkCertBundle)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.StopNetworkCertBundle)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.NodePublicKey) > 0 {\n\t\ti -= len(m.NodePublicKey)\n\t\tcopy(dAtA[i:], m.NodePublicKey)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.NodePublicKey)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.PublicKey) > 0 {\n\t\ti -= len(m.PublicKey)\n\t\tcopy(dAtA[i:], m.PublicKey)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.PublicKey)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Timestamp != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.Timestamp))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.KeyId != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.KeyId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StopNetwork) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StopNetwork) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *StopNetwork) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif len(m.StopNetworkCert) > 0 {\n\t\ti -= len(m.StopNetworkCert)\n\t\tcopy(dAtA[i:], m.StopNetworkCert)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.StopNetworkCert)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Timestamp != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.Timestamp))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.KeyId != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.KeyId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TxResult) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TxResult) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *TxResult) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif len(m.Error) > 0 {\n\t\ti -= len(m.Error)\n\t\tcopy(dAtA[i:], m.Error)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.Error)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Result) > 0 {\n\t\ti -= len(m.Result)\n\t\tcopy(dAtA[i:], m.Result)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.Result)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Code != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.Code))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.BlockId != 0 {\n\t\ti = encodeVarintTx(dAtA, i, uint64(m.BlockId))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Hash) > 0 {\n\t\ti -= len(m.Hash)\n\t\tcopy(dAtA[i:], m.Hash)\n\t\ti = encodeVarintTx(dAtA, i, uint64(len(m.Hash)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc encodeVarintTx(dAtA []byte, offset int, v uint64) int {\n\toffset -= sovTx(v)\n\tbase := offset\n\tfor v >= 1<<7 {\n\t\tdAtA[offset] = uint8(v&0x7f | 0x80)\n\t\tv >>= 7\n\t\toffset++\n\t}\n\tdAtA[offset] = uint8(v)\n\treturn base\n}\nfunc (m *FirstBlock) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.KeyId != 0 {\n\t\tn += 1 + sovTx(uint64(m.KeyId))\n\t}\n\tif m.Timestamp != 0 {\n\t\tn += 1 + sovTx(uint64(m.Timestamp))\n\t}\n\tl = len(m.PublicKey)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\tl = len(m.NodePublicKey)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\tl = len(m.StopNetworkCertBundle)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\tif m.Test != 0 {\n\t\tn += 1 + sovTx(uint64(m.Test))\n\t}\n\tif m.PrivateBlockchain != 0 {\n\t\tn += 1 + sovTx(uint64(m.PrivateBlockchain))\n\t}\n\treturn n\n}\n\nfunc (m *StopNetwork) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.KeyId != 0 {\n\t\tn += 1 + sovTx(uint64(m.KeyId))\n\t}\n\tif m.Timestamp != 0 {\n\t\tn += 1 + sovTx(uint64(m.Timestamp))\n\t}\n\tl = len(m.StopNetworkCert)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\treturn n\n}\n\nfunc (m *TxResult) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hash)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\tif m.BlockId != 0 {\n\t\tn += 1 + sovTx(uint64(m.BlockId))\n\t}\n\tif m.Code != 0 {\n\t\tn += 1 + sovTx(uint64(m.Code))\n\t}\n\tl = len(m.Result)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\tl = len(m.Error)\n\tif l > 0 {\n\t\tn += 1 + l + sovTx(uint64(l))\n\t}\n\treturn n\n}\n\nfunc sovTx(x uint64) (n int) {\n\treturn (math_bits.Len64(x|1) + 6) / 7\n}\nfunc sozTx(x uint64) (n int) {\n\treturn sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63))))\n}\nfunc (m *FirstBlock) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowTx\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: FirstBlock: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: FirstBlock: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KeyId\", wireType)\n\t\t\t}\n\t\t\tm.KeyId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.KeyId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timestamp\", wireType)\n\t\t\t}\n\t\t\tm.Timestamp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timestamp |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PublicKey\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PublicKey = append(m.PublicKey[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.PublicKey == nil {\n\t\t\t\tm.PublicKey = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodePublicKey\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NodePublicKey = append(m.NodePublicKey[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.NodePublicKey == nil {\n\t\t\t\tm.NodePublicKey = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StopNetworkCertBundle\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.StopNetworkCertBundle = append(m.StopNetworkCertBundle[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.StopNetworkCertBundle == nil {\n\t\t\t\tm.StopNetworkCertBundle = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Test\", wireType)\n\t\t\t}\n\t\t\tm.Test = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Test |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrivateBlockchain\", wireType)\n\t\t\t}\n\t\t\tm.PrivateBlockchain = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PrivateBlockchain |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipTx(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StopNetwork) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowTx\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StopNetwork: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StopNetwork: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KeyId\", wireType)\n\t\t\t}\n\t\t\tm.KeyId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.KeyId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timestamp\", wireType)\n\t\t\t}\n\t\t\tm.Timestamp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timestamp |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StopNetworkCert\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.StopNetworkCert = append(m.StopNetworkCert[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.StopNetworkCert == nil {\n\t\t\t\tm.StopNetworkCert = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipTx(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TxResult) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowTx\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TxResult: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TxResult: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hash\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Hash == nil {\n\t\t\t\tm.Hash = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockId\", wireType)\n\t\t\t}\n\t\t\tm.BlockId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BlockId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Code\", wireType)\n\t\t\t}\n\t\t\tm.Code = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Code |= TxInvokeStatusCode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Result\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Result = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Error = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipTx(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthTx\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc skipTx(dAtA []byte) (n int, err error) {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tdepth := 0\n\tfor iNdEx < l {\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn 0, ErrIntOverflowTx\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= (uint64(b) & 0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\twireType := int(wire & 0x7)\n\t\tswitch wireType {\n\t\tcase 0:\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tiNdEx++\n\t\t\t\tif dAtA[iNdEx-1] < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 1:\n\t\t\tiNdEx += 8\n\t\tcase 2:\n\t\t\tvar length int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowTx\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tlength |= (int(b) & 0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif length < 0 {\n\t\t\t\treturn 0, ErrInvalidLengthTx\n\t\t\t}\n\t\t\tiNdEx += length\n\t\tcase 3:\n\t\t\tdepth++\n\t\tcase 4:\n\t\t\tif depth == 0 {\n\t\t\t\treturn 0, ErrUnexpectedEndOfGroupTx\n\t\t\t}\n\t\t\tdepth--\n\t\tcase 5:\n\t\t\tiNdEx += 4\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"proto: illegal wireType %d\", wireType)\n\t\t}\n\t\tif iNdEx < 0 {\n\t\t\treturn 0, ErrInvalidLengthTx\n\t\t}\n\t\tif depth == 0 {\n\t\t\treturn iNdEx, nil\n\t\t}\n\t}\n\treturn 0, io.ErrUnexpectedEOF\n}\n\nvar (\n\tErrInvalidLengthTx        = fmt.Errorf(\"proto: negative length found during unmarshaling\")\n\tErrIntOverflowTx          = fmt.Errorf(\"proto: integer overflow\")\n\tErrUnexpectedEndOfGroupTx = fmt.Errorf(\"proto: unexpected end of group\")\n)\n"
  },
  {
    "path": "packages/protocols/block_counter.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage protocols\n\nimport \"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\ntype intervalBlocksCounter interface {\n\tcount(state blockGenerationState) (int, error)\n}\n\ntype blocksCounter struct {\n}\n\nfunc (bc *blocksCounter) count(state blockGenerationState) (int, error) {\n\tblockchain := &sqldb.BlockChain{}\n\tblocks, err := blockchain.GetNodeBlocksAtTime(state.start, state.start.Add(state.duration), state.nodePosition)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn len(blocks), nil\n}\n"
  },
  {
    "path": "packages/protocols/block_counter_mock.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage protocols\n\nimport \"github.com/stretchr/testify/mock\"\n\n// mockIntervalBlocksCounter is an autogenerated mock type for the intervalBlocksCounter type\ntype mockIntervalBlocksCounter struct {\n\tmock.Mock\n}\n\n// count provides a mock function with given fields: state\nfunc (_m *mockIntervalBlocksCounter) count(state blockGenerationState) (int, error) {\n\tret := _m.Called(state)\n\n\tvar r0 int\n\tif rf, ok := ret.Get(0).(func(blockGenerationState) int); ok {\n\t\tr0 = rf(state)\n\t} else {\n\t\tr0 = ret.Get(0).(int)\n\t}\n\n\tvar r1 error\n\tif rf, ok := ret.Get(1).(func(blockGenerationState) error); ok {\n\t\tr1 = rf(state)\n\t} else {\n\t\tr1 = ret.Error(1)\n\t}\n\n\treturn r0, r1\n}\n"
  },
  {
    "path": "packages/protocols/block_time_calculator.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage protocols\n\nimport (\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// BlockTimeCalculator calculating block generation time\ntype BlockTimeCalculator struct {\n\tclock         utils.Clock\n\tblocksCounter intervalBlocksCounter\n\n\tfirstBlockTime      time.Time\n\tblockGenerationTime time.Duration\n\tblocksGap           time.Duration\n\n\tnodesCount int64\n}\n\ntype blockGenerationState struct {\n\tstart    time.Time\n\tduration time.Duration\n\n\tnodePosition int64\n}\n\nfunc NewBlockTimeCalculator(firstBlockTime time.Time, generationTime, blocksGap time.Duration, nodesCount int64) BlockTimeCalculator {\n\treturn BlockTimeCalculator{\n\t\tclock:         &utils.ClockWrapper{},\n\t\tblocksCounter: &blocksCounter{},\n\n\t\tfirstBlockTime:      firstBlockTime,\n\t\tblockGenerationTime: generationTime,\n\t\tblocksGap:           blocksGap,\n\t\tnodesCount:          nodesCount,\n\t}\n}\n\nfunc (btc *BlockTimeCalculator) TimeToGenerate(nodePosition int64) (bool, error) {\n\tbgs, err := btc.countBlockTime(btc.clock.Now())\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tblocks, err := btc.blocksCounter.count(bgs)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif blocks != 0 {\n\t\treturn false, DuplicateBlockError\n\t}\n\n\treturn bgs.nodePosition == nodePosition, nil\n}\n\nfunc (btc *BlockTimeCalculator) ValidateBlock(nodePosition int64, at time.Time) (bool, error) {\n\tbgs, err := btc.countBlockTime(at)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tblocks, err := btc.blocksCounter.count(bgs)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif blocks != 0 {\n\t\treturn false, DuplicateBlockError\n\t}\n\n\treturn bgs.nodePosition == nodePosition, nil\n}\n\nfunc (btc *BlockTimeCalculator) SetClock(clock utils.Clock) *BlockTimeCalculator {\n\tbtc.clock = clock\n\treturn btc\n}\n\nfunc (btc *BlockTimeCalculator) setBlockCounter(counter intervalBlocksCounter) *BlockTimeCalculator {\n\tbtc.blocksCounter = counter\n\treturn btc\n}\n\nfunc (btc *BlockTimeCalculator) countBlockTime(blockTime time.Time) (blockGenerationState, error) {\n\tbgs := blockGenerationState{}\n\tnextBlockStart := btc.firstBlockTime\n\tvar curNodeIndex int64\n\n\tif blockTime.Before(nextBlockStart) {\n\t\treturn blockGenerationState{}, TimeError\n\t}\n\n\tfor {\n\t\tcurBlockStart := nextBlockStart\n\t\tcurBlockEnd := curBlockStart.Add(btc.blocksGap + btc.blockGenerationTime)\n\t\tnextBlockStart = curBlockEnd.Add(time.Second)\n\n\t\tif blockTime.Equal(curBlockStart) || blockTime.After(curBlockStart) && blockTime.Before(nextBlockStart) {\n\t\t\tbgs.start = curBlockStart\n\t\t\tbgs.duration = btc.blocksGap + btc.blockGenerationTime\n\t\t\tbgs.nodePosition = curNodeIndex\n\t\t\treturn bgs, nil\n\t\t}\n\n\t\tif btc.nodesCount > 0 {\n\t\t\tcurNodeIndex = (curNodeIndex + 1) % btc.nodesCount\n\t\t}\n\t}\n}\n\nfunc BuildBlockTimeCalculator(transaction *sqldb.DbTransaction) (BlockTimeCalculator, error) {\n\tvar btc BlockTimeCalculator\n\tfirstBlock := sqldb.BlockChain{}\n\tfound, err := firstBlock.Get(1)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting first block\")\n\t\treturn btc, err\n\t}\n\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound, \"error\": err}).Error(\"first block not found\")\n\t\treturn btc, err\n\t}\n\n\tblockGenerationDuration := time.Millisecond * time.Duration(syspar.GetMaxBlockGenerationTime())\n\tblocksGapDuration := time.Second * time.Duration(syspar.GetGapsBetweenBlocks())\n\n\tbtc = NewBlockTimeCalculator(time.Unix(firstBlock.Time, 0),\n\t\tblockGenerationDuration,\n\t\tblocksGapDuration,\n\t\tsyspar.GetNumberOfNodesFromDB(transaction),\n\t)\n\treturn btc, nil\n}\n"
  },
  {
    "path": "packages/protocols/block_time_calculator_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage protocols\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBlockTimeCalculator_TimeToGenerate(t *testing.T) {\n\tcases := []struct {\n\t\tfirstBlockTime time.Time\n\t\tblockGenTime   time.Duration\n\t\tblocksGap      time.Duration\n\t\tnodesCount     int64\n\t\tclock          utils.Clock\n\t\tblocksCounter  intervalBlocksCounter\n\t\tnodePosition   int64\n\n\t\tresult bool\n\t\terr    error\n\t}{\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\n\t\t\tclock: func() utils.Clock {\n\t\t\t\tmc := &utils.MockClock{}\n\t\t\t\tmc.On(\"Now\").Return(time.Unix(0, 0))\n\t\t\t\treturn mc\n\t\t\t}(),\n\n\t\t\terr: TimeError,\n\t\t},\n\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     3,\n\t\t\tnodePosition:   2,\n\n\t\t\tclock: func() utils.Clock {\n\t\t\t\tmc := &utils.MockClock{}\n\t\t\t\tmc.On(\"Now\").Return(time.Unix(16, 0))\n\t\t\t\treturn mc\n\t\t\t}(),\n\t\t\tblocksCounter: func() intervalBlocksCounter {\n\t\t\t\tibc := &mockIntervalBlocksCounter{}\n\t\t\t\tibc.On(\"count\", blockGenerationState{\n\t\t\t\t\tstart:        time.Unix(13, 0),\n\t\t\t\t\tduration:     time.Second * 5,\n\t\t\t\t\tnodePosition: 2,\n\t\t\t\t}).Return(1, nil)\n\t\t\t\treturn ibc\n\t\t\t}(),\n\n\t\t\tresult: false,\n\t\t\terr:    DuplicateBlockError,\n\t\t},\n\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     3,\n\t\t\tnodePosition:   2,\n\n\t\t\tclock: func() utils.Clock {\n\t\t\t\tmc := &utils.MockClock{}\n\t\t\t\tmc.On(\"Now\").Return(time.Unix(16, 0))\n\t\t\t\treturn mc\n\t\t\t}(),\n\t\t\tblocksCounter: func() intervalBlocksCounter {\n\t\t\t\tibc := &mockIntervalBlocksCounter{}\n\t\t\t\tibc.On(\"count\", blockGenerationState{\n\t\t\t\t\tstart:        time.Unix(13, 0),\n\t\t\t\t\tduration:     time.Second * 5,\n\t\t\t\t\tnodePosition: 2,\n\t\t\t\t}).Return(0, nil)\n\t\t\t\treturn ibc\n\t\t\t}(),\n\n\t\t\tresult: true,\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tbtc := NewBlockTimeCalculator(c.firstBlockTime,\n\t\t\tc.blockGenTime,\n\t\t\tc.blocksGap,\n\t\t\tc.nodesCount,\n\t\t)\n\n\t\texecResult, execErr := btc.\n\t\t\tSetClock(c.clock).\n\t\t\tsetBlockCounter(c.blocksCounter).\n\t\t\tTimeToGenerate(c.nodePosition)\n\n\t\trequire.Equal(t, c.err, execErr)\n\t\tassert.Equal(t, c.result, execResult)\n\t}\n}\n\nfunc TestBlockTimeCalculator_ValidateBlock(t *testing.T) {\n\tcases := []struct {\n\t\tfirstBlockTime time.Time\n\t\tblockGenTime   time.Duration\n\t\tblocksGap      time.Duration\n\t\tnodesCount     int64\n\t\ttime           time.Time\n\t\tblocksCounter  intervalBlocksCounter\n\t\tnodePosition   int64\n\n\t\tresult bool\n\t\terr    error\n\t}{\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\ttime:           time.Unix(0, 0),\n\n\t\t\terr: TimeError,\n\t\t},\n\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     3,\n\t\t\tnodePosition:   2,\n\n\t\t\ttime: time.Unix(16, 0),\n\t\t\tblocksCounter: func() intervalBlocksCounter {\n\t\t\t\tibc := &mockIntervalBlocksCounter{}\n\t\t\t\tibc.On(\"count\", blockGenerationState{\n\t\t\t\t\tstart:        time.Unix(13, 0),\n\t\t\t\t\tduration:     time.Second * 5,\n\t\t\t\t\tnodePosition: 2,\n\t\t\t\t}).Return(1, nil)\n\t\t\t\treturn ibc\n\t\t\t}(),\n\n\t\t\tresult: false,\n\t\t\terr:    DuplicateBlockError,\n\t\t},\n\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     3,\n\t\t\tnodePosition:   2,\n\n\t\t\ttime: time.Unix(16, 0),\n\t\t\tblocksCounter: func() intervalBlocksCounter {\n\t\t\t\tibc := &mockIntervalBlocksCounter{}\n\t\t\t\tibc.On(\"count\", blockGenerationState{\n\t\t\t\t\tstart:        time.Unix(13, 0),\n\t\t\t\t\tduration:     time.Second * 5,\n\t\t\t\t\tnodePosition: 2,\n\t\t\t\t}).Return(0, nil)\n\t\t\t\treturn ibc\n\t\t\t}(),\n\n\t\t\tresult: true,\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tbtc := NewBlockTimeCalculator(c.firstBlockTime,\n\t\t\tc.blockGenTime,\n\t\t\tc.blocksGap,\n\t\t\tc.nodesCount,\n\t\t)\n\n\t\texecResult, execErr := btc.\n\t\t\tsetBlockCounter(c.blocksCounter).\n\t\t\tValidateBlock(c.nodePosition, c.time)\n\n\t\trequire.Equal(t, c.err, execErr)\n\t\tassert.Equal(t, c.result, execResult)\n\t}\n}\n\nfunc TestBlockTImeCalculator_countBlockTime(t *testing.T) {\n\tcases := []struct {\n\t\tfirstBlockTime time.Time\n\t\tblockGenTime   time.Duration\n\t\tblocksGap      time.Duration\n\t\tnodesCount     int64\n\t\tclock          time.Time\n\n\t\tresult blockGenerationState\n\t\terr    error\n\t}{\n\t\t// Current time before first block case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tclock:          time.Unix(0, 0),\n\n\t\t\terr: TimeError,\n\t\t},\n\n\t\t// Zero duration case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 0,\n\t\t\tblocksGap:      time.Second * 0,\n\t\t\tnodesCount:     5,\n\t\t\tclock:          time.Unix(0, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(0, 0),\n\t\t\t\tduration: time.Second * 0,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Duration testing case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 1,\n\t\t\tblocksGap:      time.Second * 0,\n\t\t\tnodesCount:     5,\n\t\t\tclock:          time.Unix(0, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(0, 0),\n\t\t\t\tduration: time.Second * 1,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Duration testing case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 0,\n\t\t\tblocksGap:      time.Second * 1,\n\t\t\tnodesCount:     5,\n\t\t\tclock:          time.Unix(0, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(0, 0),\n\t\t\t\tduration: time.Second * 1,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Duration testing case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 4,\n\t\t\tblocksGap:      time.Second * 6,\n\t\t\tnodesCount:     5,\n\t\t\tclock:          time.Unix(0, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(0, 0),\n\t\t\t\tduration: time.Second * 10,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Block lowest time boundary case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 1,\n\t\t\tblocksGap:      time.Second * 1,\n\t\t\tnodesCount:     10,\n\t\t\tclock:          time.Unix(0, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(0, 0),\n\t\t\t\tduration: time.Second * 2,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Block highest time boundary case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     10,\n\t\t\tclock:          time.Unix(5, 999999999),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(0, 0),\n\t\t\t\tduration: time.Second * 5,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Last nodePosition case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 0,\n\t\t\tblocksGap:      time.Second * 1,\n\t\t\tnodesCount:     3,\n\t\t\tclock:          time.Unix(6, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(6, 0),\n\t\t\t\tduration: time.Second * 1,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// One node case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(0, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 2,\n\t\t\tnodesCount:     1,\n\t\t\tclock:          time.Unix(6, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(5, 0),\n\t\t\t\tduration: time.Second * 4,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\n\t\t// Custom firstBlockTime case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     3,\n\t\t\tclock:          time.Unix(13, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(13, 0),\n\t\t\t\tduration: time.Second * 5,\n\n\t\t\t\tnodePosition: 2,\n\t\t\t},\n\t\t},\n\n\t\t// Current time is in middle of interval case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1, 0),\n\t\t\tblockGenTime:   time.Second * 2,\n\t\t\tblocksGap:      time.Second * 3,\n\t\t\tnodesCount:     3,\n\t\t\tclock:          time.Unix(16, 0),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(13, 0),\n\t\t\t\tduration: time.Second * 5,\n\n\t\t\t\tnodePosition: 2,\n\t\t\t},\n\t\t},\n\n\t\t// Real life case\n\t\t{\n\t\t\tfirstBlockTime: time.Unix(1519240000, 0),\n\t\t\tblockGenTime:   time.Second * 4,\n\t\t\tblocksGap:      time.Second * 5,\n\t\t\tnodesCount:     101,\n\t\t\tclock:          time.Unix(1519241010, 1234),\n\n\t\t\tresult: blockGenerationState{\n\t\t\t\tstart:    time.Unix(1519241010, 0),\n\t\t\t\tduration: time.Second * 9,\n\n\t\t\t\tnodePosition: 0,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tbtc := NewBlockTimeCalculator(c.firstBlockTime,\n\t\t\tc.blockGenTime,\n\t\t\tc.blocksGap,\n\t\t\tc.nodesCount,\n\t\t)\n\n\t\texecResult, execErr := btc.countBlockTime(c.clock)\n\t\trequire.Equal(t, c.err, execErr)\n\t\tassert.Equal(t, c.result, execResult)\n\t}\n}\n"
  },
  {
    "path": "packages/protocols/block_time_counter_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage protocols\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBlockTimeCounter(t *testing.T) {\n\tbtc := BlockTimeCounter{\n\t\tstart:       time.Unix(0, 0),\n\t\tduration:    5 * time.Second,\n\t\tnumberNodes: 3,\n\t}\n\n\tat := time.Unix(13, 0)\n\n\tqueue, err := btc.queue(at)\n\tassert.NoError(t, err)\n\tassert.Equal(t, 2, queue)\n\n\tnp, err := btc.nodePosition(at)\n\tassert.NoError(t, err)\n\tassert.Equal(t, 2, np)\n\n\tnextTime, err := btc.nextTime(at, 2)\n\tassert.NoError(t, err)\n\tassert.Equal(t, time.Unix(25, 0).Add(1*time.Millisecond), nextTime)\n\n\tstart, end, err := btc.RangeByTime(at)\n\tassert.NoError(t, err)\n\tassert.Equal(t, time.Unix(10, 0).Add(1*time.Millisecond), start)\n\tassert.Equal(t, time.Unix(15, 0), end)\n\tfmt.Println(\"ranges:\", start.Unix(), end.Unix())\n}\n\nfunc TestRangeByTime(t *testing.T) {\n\tbtc := BlockTimeCounter{\n\t\tstart:       time.Unix(1532977623, 0),\n\t\tduration:    4 * time.Second,\n\t\tnumberNodes: 1,\n\t}\n\n\tst, end, err := btc.RangeByTime(time.Unix(1533062723, 0))\n\trequire.NoError(t, err)\n\tfmt.Println(st.Unix(), end.Unix())\n\n\tst, end, err = btc.RangeByTime(time.Unix(1533062724, 0))\n\trequire.NoError(t, err)\n\tfmt.Println(st.Unix(), end.Unix())\n\n\t// 1532977623\n\tst, end, err = btc.RangeByTime(time.Unix(1532977624, 0))\n\trequire.NoError(t, err)\n\tfmt.Println(st.Unix(), end.Unix())\n\n\t// 1533062719 1533062723\n\t// 1533062723 1533062727\n\t// 1532977623 1532977627\n}\n\nfunc TestBlockOnlineTime(t *testing.T) {\n\n\tbtc := BlockTimeCounter{\n\t\tstart:       time.Unix(1607311077, 0),\n\t\tduration:    4000000000,\n\t\tnumberNodes: 3,\n\t}\n\t//node23 1607336686   node22 1607392437   1607392568  node21 1607408766  1607393213\n\texists, err := btc.NodeTimeExists(time.Unix(1607393213, 0), int(0))\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t}\n\tif exists {\n\t\tfmt.Println(\"exist\")\n\t}\n}\n"
  },
  {
    "path": "packages/protocols/generation-queue.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage protocols\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n)\n\n// BlockTimeChecker allow check queue to generate current block\ntype BlockTimeChecker interface {\n\tTimeToGenerate(position int64) (bool, error)\n\tBlockForTimeExists(t time.Time, nodePosition int) (bool, error)\n\tRangeByTime(at time.Time) (start, end time.Time, err error)\n}\n\nvar (\n\tWrongNodePositionError = errors.New(\"wrong node position\")\n\tTimeError              = errors.New(\"current time before first block\")\n\tDuplicateBlockError    = errors.New(\"block for this time interval exists\")\n)\n\ntype BlockTimeCounter struct {\n\tstart       time.Time\n\tduration    time.Duration\n\tnumberNodes int\n}\n\n// Queue returns serial queue number for time\nfunc (btc *BlockTimeCounter) queue(t time.Time) (int, error) {\n\tut := t.Unix()\n\tt = time.Unix(ut, 0)\n\tif t.Before(btc.start) {\n\t\treturn -1, TimeError\n\t}\n\n\treturn int((t.Sub(btc.start) - 1) / btc.duration), nil\n}\n\n// NodePosition returns generating node position for time\nfunc (btc *BlockTimeCounter) nodePosition(t time.Time) (int, error) {\n\tqueue, err := btc.queue(t)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\n\treturn queue % btc.numberNodes, nil\n}\n\nfunc (btc *BlockTimeCounter) NodeTimeExists(t time.Time, nodePosition int) (bool, error) {\n\tps, err := btc.nodePosition(t)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif ps == nodePosition {\n\t\treturn true, nil\n\t}\n\n\t//startInterval, endInterval, err := btc.RangeByTime(t)\n\t//if err != nil {\n\t//\treturn false, err\n\t//}\n\n\treturn false, nil\n}\n\n// BlockForTimeExists checks conformity between time and nodePosition\n// changes functionality of ValidateBlock prevent blockTimeCalculator\nfunc (btc *BlockTimeCounter) BlockForTimeExists(t time.Time, nodePosition int) (bool, error) {\n\tstartInterval, endInterval, err := btc.RangeByTime(t)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tb := &sqldb.BlockChain{}\n\tblocks, err := b.GetNodeBlocksAtTime(startInterval, endInterval, int64(nodePosition))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn len(blocks) > 0, nil\n}\n\n// NextTime returns next generation time for node position at time\nfunc (btc *BlockTimeCounter) nextTime(t time.Time, nodePosition int) (time.Time, error) {\n\tif nodePosition >= btc.numberNodes {\n\t\treturn time.Unix(0, 0), WrongNodePositionError\n\t}\n\n\tqueue, err := btc.queue(t)\n\tif err != nil {\n\t\treturn time.Unix(0, 0), err\n\t}\n\tcurNodePosition := queue % btc.numberNodes\n\n\td := nodePosition - curNodePosition\n\tif curNodePosition >= nodePosition {\n\t\td += btc.numberNodes\n\t}\n\n\treturn btc.start.Add(btc.duration*time.Duration(queue+d) + time.Millisecond), nil\n}\n\n// RangeByTime returns start and end of interval by time\nfunc (btc *BlockTimeCounter) RangeByTime(t time.Time) (start, end time.Time, err error) {\n\tqueue, err := btc.queue(t)\n\tif err != nil {\n\t\tst := time.Unix(0, 0)\n\t\treturn st, st, err\n\t}\n\n\tstart = btc.start.Add(btc.duration*time.Duration(queue) + time.Second)\n\tend = start.Add(btc.duration - time.Second)\n\treturn\n}\n\n// TimeToGenerate returns true if the generation queue at time belongs to the specified node\nfunc (btc *BlockTimeCounter) TimeToGenerate(at time.Time, nodePosition int) (bool, error) {\n\tif nodePosition >= btc.numberNodes {\n\t\treturn false, WrongNodePositionError\n\t}\n\n\tposition, err := btc.nodePosition(at)\n\treturn position == nodePosition, err\n}\n\n// NewBlockTimeCounter return initialized BlockTimeCounter\nfunc NewBlockTimeCounter() *BlockTimeCounter {\n\tbtc := BlockTimeCounter{\n\t\tstart:       time.Unix(syspar.GetFirstBlockTimestamp(), 0),\n\t\tduration:    syspar.GetMaxBlockTimeDuration(),\n\t\tnumberNodes: int(syspar.GetCountOfActiveNodes()),\n\t}\n\treturn &btc\n}\n"
  },
  {
    "path": "packages/publisher/publisher.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage publisher\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\t\"github.com/centrifugal/gocent\"\n\t\"github.com/golang-jwt/jwt/v4\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype ClientsChannels struct {\n\tstorage map[int64]string\n\tsync.RWMutex\n}\n\nfunc (cn *ClientsChannels) Set(id int64, s string) {\n\tcn.Lock()\n\tdefer cn.Unlock()\n\tcn.storage[id] = s\n}\n\nfunc (cn *ClientsChannels) Get(id int64) string {\n\tcn.RLock()\n\tdefer cn.RUnlock()\n\treturn cn.storage[id]\n}\n\nvar (\n\tclientsChannels   = ClientsChannels{storage: make(map[int64]string)}\n\tcentrifugoTimeout = time.Second * 5\n\tpublisher         *gocent.Client\n\tconfig            conf.CentrifugoConfig\n)\n\ntype CentJWT struct {\n\tSub string\n\tjwt.RegisteredClaims\n}\n\n// InitCentrifugo client\nfunc InitCentrifugo(cfg conf.CentrifugoConfig) {\n\tconfig = cfg\n\tpublisher = gocent.New(gocent.Config{\n\t\tAddr: cfg.URL,\n\t\tKey:  cfg.Key,\n\t})\n}\n\nfunc GetJWTCent(userID, expire int64) (string, string, error) {\n\ttimestamp := strconv.FormatInt(time.Now().Unix(), 10)\n\n\tcentJWT := CentJWT{\n\t\tSub: strconv.FormatInt(userID, 10),\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\tExpiresAt: &jwt.NumericDate{Time: time.Now().Add(time.Second * time.Duration(expire))},\n\t\t},\n\t}\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodHS256, centJWT)\n\tresult, err := token.SignedString([]byte(config.Secret))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"JWT centrifugo error\")\n\t\treturn \"\", \"\", err\n\t}\n\tclientsChannels.Set(userID, result)\n\treturn result, timestamp, nil\n}\n\n// Write is publishing data to server\nfunc Write(account string, data string) error {\n\tctx, cancel := context.WithTimeout(context.Background(), centrifugoTimeout)\n\tdefer cancel()\n\treturn publisher.Publish(ctx, \"client\"+account, []byte(data))\n}\n\n// GetStats returns Stats\nfunc GetStats() (gocent.InfoResult, error) {\n\tif publisher == nil {\n\t\treturn gocent.InfoResult{}, fmt.Errorf(\"publisher not initialized\")\n\t}\n\tctx, cancel := context.WithTimeout(context.Background(), centrifugoTimeout)\n\tdefer cancel()\n\treturn publisher.Info(ctx)\n}\n"
  },
  {
    "path": "packages/rollback/block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage rollback\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar (\n\tErrLastBlock = errors.New(\"block is not the last\")\n)\n\n// RollbackBlock is blocking rollback\nfunc RollbackBlock(data []byte) error {\n\tbl, err := block.UnmarshallBlock(bytes.NewBuffer(data), true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tb := &sqldb.BlockChain{}\n\tif _, err = b.GetMaxBlock(); err != nil {\n\t\treturn err\n\t}\n\n\tif b.ID != bl.Header.BlockId {\n\t\treturn ErrLastBlock\n\t}\n\n\tdbTx, err := sqldb.StartTransaction()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"starting transaction\")\n\t\treturn err\n\t}\n\n\terr = rollbackBlock(dbTx, bl)\n\tif err != nil {\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\n\tif err = b.DeleteById(dbTx, bl.Header.BlockId); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting block by id\")\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\n\tb = &sqldb.BlockChain{}\n\tif _, err = b.Get(bl.Header.BlockId - 1); err != nil {\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\n\tbl, err = block.UnmarshallBlock(bytes.NewBuffer(b.Data), false)\n\tif err != nil {\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\n\tib := &sqldb.InfoBlock{\n\t\tHash:           b.Hash,\n\t\tRollbacksHash:  b.RollbacksHash,\n\t\tBlockID:        b.ID,\n\t\tNodePosition:   strconv.Itoa(int(b.NodePosition)),\n\t\tKeyID:          b.KeyID,\n\t\tTime:           b.Time,\n\t\tCurrentVersion: strconv.Itoa(int(bl.Header.Version)),\n\t\tConsensusMode:  b.ConsensusMode,\n\t\tCandidateNodes: b.CandidateNodes,\n\t}\n\terr = ib.Update(dbTx)\n\tif err != nil {\n\t\tdbTx.Rollback()\n\t\treturn err\n\t}\n\n\treturn dbTx.Commit()\n}\n\nfunc rollbackBlock(dbTx *sqldb.DbTransaction, block *block.Block) error {\n\t// rollback transactions in reverse order\n\tlogger := block.GetLogger()\n\tvar transferSelfHashes = make([]string, 0)\n\tfor i := len(block.Transactions) - 1; i >= 0; i-- {\n\t\tt := block.Transactions[i]\n\t\tt.DbTransaction = dbTx\n\n\t\t_, err := sqldb.MarkTransactionUnusedAndUnverified(dbTx, t.Hash())\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"starting transaction\")\n\t\t\treturn err\n\t\t}\n\t\t_, err = sqldb.DeleteLogTransactionsByHash(dbTx, t.Hash())\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting log transactions by hash\")\n\t\t\treturn err\n\t\t}\n\n\t\tts := &sqldb.TransactionStatus{}\n\t\terr = ts.UpdateBlockID(dbTx, 0, t.Hash())\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating block id in transaction status\")\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = sqldb.DeleteQueueTxByHash(dbTx, t.Hash())\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting transacion from queue by hash\")\n\t\t\treturn err\n\t\t}\n\n\t\tswitch t.Inner.(type) {\n\t\tcase *transaction.SmartTransactionParser:\n\t\t\tt.Inner.(*transaction.SmartTransactionParser).DbTransaction = t.DbTransaction\n\t\t\tif err = rollbackTransaction(t.Hash(), t.DbTransaction, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ttransferSelf := t.Inner.(*transaction.SmartTransactionParser).TxSmart.TransferSelf\n\t\t\tif transferSelf != nil {\n\t\t\t\tif strings.EqualFold(\"UTXO\", transferSelf.Source) && strings.EqualFold(\"Account\", transferSelf.Target) {\n\t\t\t\t\ttransferSelfHashes = append(transferSelfHashes, fmt.Sprintf(\"%x\", t.Hash()))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\terr = t.Inner.TxRollback()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\terr := sqldb.RollbackOutputs(block.Header.BlockId, dbTx, transferSelfHashes, logger)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating outputs by block id\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/rollback/rollback.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage rollback\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// ToBlockID rollbacks blocks till blockID\nfunc ToBlockID(blockID int64, dbTx *sqldb.DbTransaction, logger *log.Entry) error {\n\t_, err := sqldb.MarkVerifiedAndNotUsedTransactionsUnverified()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"marking verified and not used transactions unverified\")\n\t\treturn err\n\t}\n\n\t// roll back our blocks\n\tfor {\n\t\tblock := &sqldb.BlockChain{}\n\t\tblocks, err := block.GetBlocks(blockID, syspar.GetMaxTxCount())\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting blocks\")\n\t\t\treturn err\n\t\t}\n\t\tif len(blocks) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tfor _, block := range blocks {\n\t\t\t// roll back our blocks to the block blockID\n\t\t\terr = RollbackBlock(block.Data)\n\t\t\tif err != nil {\n\t\t\t\treturn errors.WithMessagef(err, \"block_id: %d\", block.ID)\n\t\t\t}\n\t\t\tlogger.WithFields(log.Fields{\"rollback_tx\": block.Tx}).Infof(\"rollback %d successful\", block.ID)\n\t\t}\n\t\tblocks = blocks[:0]\n\t}\n\tblock := &sqldb.BlockChain{}\n\t_, err = block.Get(blockID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting block\")\n\t\treturn err\n\t}\n\n\theader, err := types.ParseBlockHeader(bytes.NewBuffer(block.Data), syspar.GetMaxBlockSize())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tib := &sqldb.InfoBlock{\n\t\tHash:           block.Hash,\n\t\tBlockID:        header.BlockId,\n\t\tTime:           header.Timestamp,\n\t\tEcosystemID:    header.EcosystemId,\n\t\tKeyID:          header.KeyId,\n\t\tNodePosition:   converter.Int64ToStr(header.NodePosition),\n\t\tCurrentVersion: strconv.Itoa(int(header.Version)),\n\t\tRollbacksHash:  block.RollbacksHash,\n\t\tConsensusMode:  block.ConsensusMode,\n\t\tCandidateNodes: block.CandidateNodes,\n\t}\n\n\terr = ib.Update(dbTx)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating info block\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/rollback/transaction.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage rollback\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc rollbackUpdatedRow(tx map[string]string, where string, dbTx *sqldb.DbTransaction, logger *log.Entry) error {\n\tvar rollbackInfo map[string]string\n\tif err := json.Unmarshal([]byte(tx[\"data\"]), &rollbackInfo); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling rollback.Data from json\")\n\t\treturn err\n\t}\n\taddSQLUpdate := \"\"\n\tfor k, v := range rollbackInfo {\n\t\tk = `\"` + strings.Trim(k, `\"`) + `\"`\n\t\tif v == \"NULL\" {\n\t\t\taddSQLUpdate += k + `=NULL,`\n\t\t} else if syspar.IsByteColumn(tx[\"table_name\"], k) && len(v) != 0 {\n\t\t\taddSQLUpdate += k + `=decode('` + v + `','HEX'),`\n\t\t} else {\n\t\t\taddSQLUpdate += k + `='` + strings.Replace(v, `'`, `''`, -1) + `',`\n\t\t}\n\t}\n\taddSQLUpdate = addSQLUpdate[0 : len(addSQLUpdate)-1]\n\tif err := dbTx.Update(tx[\"table_name\"], addSQLUpdate, where); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err, \"rollback_id\": tx[\"id\"], \"block_id\": tx[\"block_id\"], \"where\": where}).Error(\"updating table for rollback \")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc rollbackInsertedRow(tx map[string]string, where string, dbTx *sqldb.DbTransaction, logger *log.Entry) error {\n\tif err := dbTx.Delete(tx[\"table_name\"], where); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"rollback_id\": tx[\"id\"], \"table\": tx[\"table_name\"], \"where\": where}).Error(\"deleting from table for rollback\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc rollbackTransaction(txHash []byte, dbTx *sqldb.DbTransaction, logger *log.Entry) error {\n\trollbackTx := &sqldb.RollbackTx{}\n\ttxs, err := rollbackTx.GetRollbackTransactions(dbTx, txHash)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting rollback transactions\")\n\t\treturn err\n\t}\n\tfor _, tx := range txs {\n\t\tif tx[\"table_name\"] == smart.SysName {\n\t\t\tvar sysData smart.SysRollData\n\t\t\terr := json.Unmarshal([]byte(tx[\"data\"]), &sysData)\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling rollback.Data from json\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tswitch sysData.Type {\n\t\t\tcase \"NewTable\":\n\t\t\t\terr = smart.SysRollbackTable(dbTx, sysData)\n\t\t\tcase \"NewView\":\n\t\t\t\terr = smart.SysRollbackView(dbTx, sysData)\n\t\t\tcase \"NewColumn\":\n\t\t\t\terr = smart.SysRollbackColumn(dbTx, sysData)\n\t\t\tcase \"NewContract\":\n\t\t\t\terr = smart.SysRollbackNewContract(sysData, tx[\"table_id\"])\n\t\t\tcase \"EditContract\":\n\t\t\t\terr = smart.SysRollbackEditContract(dbTx, sysData, tx[\"table_id\"])\n\t\t\tcase \"NewEcosystem\":\n\t\t\t\terr = smart.SysRollbackEcosystem(dbTx, sysData)\n\t\t\tcase \"ActivateContract\":\n\t\t\t\terr = smart.SysRollbackActivate(sysData)\n\t\t\tcase \"DeactivateContract\":\n\t\t\t\terr = smart.SysRollbackDeactivate(sysData)\n\t\t\tcase \"DeleteColumn\":\n\t\t\t\terr = smart.SysRollbackDeleteColumn(dbTx, sysData)\n\t\t\tcase \"DeleteTable\":\n\t\t\t\terr = smart.SysRollbackDeleteTable(dbTx, sysData)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\ttable := tx[`table_name`]\n\t\tvar (\n\t\t\trollbackInfo   map[string]string\n\t\t\tecoID, keyName string\n\t\t\tisFirstTable   bool\n\t\t)\n\t\tif len(tx[\"data\"]) > 0 {\n\t\t\tif err := json.Unmarshal([]byte(tx[\"data\"]), &rollbackInfo); err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling rollback.Data from json\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif len(rollbackInfo) > 0 {\n\t\t\t\tif v, ok := rollbackInfo[\"ecosystem\"]; ok {\n\t\t\t\t\tecoID = v\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif under := strings.IndexByte(table, '_'); under > 0 {\n\t\t\tkeyName = table[under+1:]\n\t\t\tif v, ok := converter.FirstEcosystemTables[keyName]; ok && v {\n\t\t\t\tisFirstTable = true\n\t\t\t}\n\t\t}\n\t\twhere := ` WHERE \"id\"='`\n\n\t\tif len(tx[\"data\"]) <= 0 {\n\t\t\tif isFirstTable {\n\t\t\t\tvar a []string\n\t\t\t\tif strings.Contains(tx[\"table_id\"], \",\") {\n\t\t\t\t\ta = strings.Split(tx[\"table_id\"], \",\")\n\t\t\t\t\tecoID = a[1]\n\t\t\t\t\twhere += a[0] + `'`\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif len(tx[\"data\"]) > 0 && isFirstTable {\n\t\t\twhere += tx[\"table_id\"] + `'`\n\t\t}\n\t\tif isFirstTable {\n\t\t\twhere += fmt.Sprintf(` AND \"ecosystem\"='%d'`, converter.StrToInt64(ecoID))\n\t\t\ttx[`table_name`] = `1_` + keyName\n\t\t} else {\n\t\t\twhere += tx[\"table_id\"] + `'`\n\t\t}\n\t\tif len(tx[\"data\"]) > 0 {\n\t\t\tif err := rollbackUpdatedRow(tx, where, dbTx, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tif err := rollbackInsertedRow(tx, where, dbTx, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\ttxForDelete := &sqldb.RollbackTx{TxHash: txHash}\n\terr = txForDelete.DeleteByHash(dbTx)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting rollback transaction by hash\")\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/scheduler/contract/request.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage contract\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\theaderAuthPrefix = \"Bearer \"\n)\n\ntype authResult struct {\n\tUID   string `json:\"uid,omitempty\"`\n\tToken string `json:\"token,omitempty\"`\n}\n\ntype contractResult struct {\n\tHash string `json:\"hash\"`\n\t// These fields are used for CLB\n\tMessage struct {\n\t\tType  string `json:\"type,omitempty\"`\n\t\tError string `json:\"error,omitempty\"`\n\t} `json:\"errmsg,omitempty\"`\n\tResult string `json:\"result,omitempty\"`\n}\n\n// NodeContract creates a transaction to execute the contract.\n// The transaction is signed with a node key.\nfunc NodeContract(Name string) (result contractResult, err error) {\n\tvar (\n\t\tsign                          []byte\n\t\tret                           authResult\n\t\tNodePrivateKey, NodePublicKey string\n\t)\n\terr = sendAPIRequest(`GET`, `getuid`, nil, &ret, ``)\n\tif err != nil {\n\t\treturn\n\t}\n\tauth := ret.Token\n\tif len(ret.UID) == 0 {\n\t\terr = fmt.Errorf(`getuid has returned empty uid`)\n\t\treturn\n\t}\n\tNodePrivateKey, NodePublicKey = utils.GetNodeKeys()\n\tif len(NodePrivateKey) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"node private key is empty\")\n\t\terr = errors.New(`empty node private key`)\n\t\treturn\n\t}\n\tsign, err = crypto.SignString(NodePrivateKey, ret.UID)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"signing node uid\")\n\t\treturn\n\t}\n\tform := url.Values{\"pubkey\": {NodePublicKey}, \"signature\": {hex.EncodeToString(sign)},\n\t\t`ecosystem`: {converter.Int64ToStr(1)}}\n\tvar logret authResult\n\terr = sendAPIRequest(`POST`, `login`, &form, &logret, auth)\n\tif err != nil {\n\t\treturn\n\t}\n\tauth = logret.Token\n\tform = url.Values{`clb`: {`true`}}\n\terr = sendAPIRequest(`POST`, `node/`+Name, &form, &result, auth)\n\tif err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc sendAPIRequest(rtype, url string, form *url.Values, v any, auth string) error {\n\tclient := &http.Client{}\n\tvar ioform io.Reader\n\tif form != nil {\n\t\tioform = strings.NewReader(form.Encode())\n\t}\n\treq, err := http.NewRequest(rtype, fmt.Sprintf(`http://%s:%d%s%s`, conf.Config.HTTP.Host,\n\t\tconf.Config.HTTP.Port, consts.ApiPath, url), ioform)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"new api request\")\n\t\treturn err\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\tif len(auth) > 0 {\n\t\treq.Header.Set(\"Authorization\", headerAuthPrefix+auth)\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"api request\")\n\t\treturn err\n\t}\n\n\tdefer resp.Body.Close()\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading api answer\")\n\t\treturn err\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NetworkError, \"error\": err}).Error(\"api status code\")\n\t\treturn fmt.Errorf(`%d %s`, resp.StatusCode, strings.TrimSpace(string(data)))\n\t}\n\n\tif err = json.Unmarshal(data, v); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling api answer\")\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/scheduler/contract/task.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage contract\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/scheduler\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// ContractHandler represents contract handler\ntype ContractHandler struct {\n\tContract string\n}\n\n// Run executes task\nfunc (ch *ContractHandler) Run(t *scheduler.Task) {\n\t_, err := NodeContract(ch.Contract)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ContractError, \"error\": err, \"task\": t.String(), \"contract\": ch.Contract}).Error(\"run contract task\")\n\t\treturn\n\t}\n\n\tlog.WithFields(log.Fields{\"task\": t.String(), \"contract\": ch.Contract}).Info(\"run contract task\")\n}\n"
  },
  {
    "path": "packages/scheduler/scheduler.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage scheduler\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\t\"github.com/robfig/cron/v3\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar scheduler *Scheduler\n\nfunc init() {\n\tscheduler = NewScheduler()\n}\n\n// Scheduler represents wrapper over the cron library\ntype Scheduler struct {\n\tcron *cron.Cron\n}\n\n// AddTask adds task to cron\nfunc (s *Scheduler) AddTask(t *Task) error {\n\terr := t.ParseCron()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.cron.Schedule(t, t)\n\tlog.WithFields(log.Fields{\"task\": t.String()}).Info(\"task added\")\n\n\treturn nil\n}\n\n// UpdateTask updates task\nfunc (s *Scheduler) UpdateTask(t *Task) error {\n\terr := t.ParseCron()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"error\": err}).Error(\"parse cron format\")\n\t\treturn err\n\t}\n\n\ts.cron.Stop()\n\tdefer s.cron.Start()\n\n\tentries := s.cron.Entries()\n\tfor _, entry := range entries {\n\t\ttask := entry.Schedule.(*Task)\n\t\tif task.ID == t.ID {\n\t\t\t*task = *t\n\t\t\tlog.WithFields(log.Fields{\"task\": t.String()}).Info(\"task updated\")\n\t\t\treturn nil\n\t\t}\n\n\t\tcontinue\n\t}\n\n\ts.cron.Schedule(t, t)\n\tlog.WithFields(log.Fields{\"task\": t.String()}).Info(\"task added\")\n\n\treturn nil\n}\n\n// NewScheduler creates a new scheduler\nfunc NewScheduler() *Scheduler {\n\ts := &Scheduler{cron: cron.New()}\n\ts.cron.Start()\n\treturn s\n}\n\n// AddTask adds task to global scheduler\nfunc AddTask(t *Task) error {\n\treturn scheduler.AddTask(t)\n}\n\n// UpdateTask updates task in global scheduler\nfunc UpdateTask(t *Task) error {\n\treturn scheduler.UpdateTask(t)\n}\n\n// Parse parses cron format\nfunc Parse(cronSpec string) (cron.Schedule, error) {\n\tsch, err := cron.ParseStandard(cronSpec)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"error\": err}).Error(\"parse cron format\")\n\t\treturn nil, err\n\t}\n\treturn sch, nil\n}\n"
  },
  {
    "path": "packages/scheduler/scheduler_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage scheduler\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestParse(t *testing.T) {\n\tcases := map[string]string{\n\t\t\"60 * * * *\":              \"End of range (60) above maximum (59): 60\",\n\t\t\"0-59 0-23 1-31 1-12 0-6\": \"\",\n\t\t\"*/2 */2 */2 */2 */2\":     \"\",\n\t\t\"* * * * *\":               \"\",\n\t}\n\n\tfor cronSpec, expectedErr := range cases {\n\t\t_, err := Parse(cronSpec)\n\t\tif err != nil {\n\t\t\tif errStr := err.Error(); errStr != expectedErr {\n\t\t\t\tt.Errorf(\"cron: %s, expected: %s, got: %s\\n\", cronSpec, expectedErr, errStr)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif expectedErr != \"\" {\n\t\t\tt.Errorf(\"cron: %s, error: %s\\n\", cronSpec, err)\n\t\t}\n\t}\n}\n\ntype mockHandler struct {\n\tcount int\n}\n\nfunc (mh *mockHandler) Run(t *Task) {\n\tmh.count++\n}\n\n// This test required timeout 60s\n// go test -timeout 60s\nfunc TestTask(t *testing.T) {\n\tvar taskID = \"task1\"\n\tsch := NewScheduler()\n\n\ttask := &Task{ID: taskID}\n\n\tnextTime := task.Next(time.Now())\n\tif nextTime != zeroTime {\n\t\tt.Error(\"error\")\n\t}\n\n\ttask = &Task{CronSpec: \"60 * * * *\"}\n\terr := sch.AddTask(task)\n\tif errStr := err.Error(); errStr != \"End of range (60) above maximum (59): 60\" {\n\t\tt.Error(err)\n\t}\n\terr = sch.UpdateTask(task)\n\tif errStr := err.Error(); errStr != \"End of range (60) above maximum (59): 60\" {\n\t\tt.Error(err)\n\t}\n\n\terr = sch.UpdateTask(&Task{ID: \"task2\"})\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n\n\thandler := &mockHandler{}\n\ttask = &Task{ID: taskID, CronSpec: \"* * * * *\", Handler: handler}\n\tsch.UpdateTask(task)\n\n\tnow := time.Now()\n\ttime.Sleep(task.Next(now).Sub(now) + time.Second)\n\n\tif handler.count == 0 {\n\t\tt.Error(\"task not running\")\n\t}\n}\n"
  },
  {
    "path": "packages/scheduler/task.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage scheduler\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/robfig/cron/v3\"\n)\n\nvar zeroTime time.Time\n\n// Handler represents interface of task handler\ntype Handler interface {\n\tRun(*Task)\n}\n\n// Task represents task\ntype Task struct {\n\tID       string\n\tCronSpec string\n\n\tHandler Handler\n\n\tschedule cron.Schedule\n}\n\n// String returns description of task\nfunc (t *Task) String() string {\n\treturn fmt.Sprintf(\"%s %s\", t.ID, t.CronSpec)\n}\n\n// ParseCron parsed cron format\nfunc (t *Task) ParseCron() error {\n\tif len(t.CronSpec) == 0 {\n\t\treturn nil\n\t}\n\n\tvar err error\n\tt.schedule, err = Parse(t.CronSpec)\n\treturn err\n}\n\n// Next returns time for next task\nfunc (t *Task) Next(tm time.Time) time.Time {\n\tif len(t.CronSpec) == 0 {\n\t\treturn zeroTime\n\t}\n\treturn t.schedule.Next(tm)\n}\n\n// Run executes task\nfunc (t *Task) Run() {\n\tt.Handler.Run(t)\n}\n"
  },
  {
    "path": "packages/script/cmds_list.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nconst (\n\t//\tcmdUnknown = iota // error\n\t// here are described the commands of bytecode\n\tcmdPush         = iota + 1 // Push value to stack\n\tcmdVar                     // Push variable to stack\n\tcmdExtend                  // Push extend variable to stack\n\tcmdCallExtend              // Call extend function\n\tcmdPushStr                 // Push ident as string\n\tcmdCall                    // call a function\n\tcmdCallVariadic            // call a variadic function\n\tcmdReturn                  // return from function\n\tcmdIf                      // run block if Value is true\n\tcmdElse                    // run block if Value is false\n\tcmdAssignVar               // list of assigned var\n\tcmdAssign                  // assign\n\tcmdLabel                   // label for continue\n\tcmdContinue                // continue from label\n\tcmdWhile                   // while\n\tcmdBreak                   // break\n\tcmdIndex                   // get index []\n\tcmdSetIndex                // set index []\n\tcmdFuncName                // set func name Func(...).Name(...)\n\tcmdUnwrapArr               // unwrap array to stack\n\tcmdMapInit                 // map initialization\n\tcmdArrayInit               // array initialization\n\tcmdError                   // error command\n)\n\n// the commands for operations in expressions are listed below\nconst (\n\tcmdNot = iota | 0x0100\n\tcmdSign\n)\n\nconst (\n\tcmdAdd = iota | 0x0200\n\tcmdSub\n\tcmdMul\n\tcmdDiv\n\tcmdAnd\n\tcmdOr\n\tcmdEqual\n\tcmdNotEq\n\tcmdLess\n\tcmdNotLess\n\tcmdGreat\n\tcmdNotGreat\n\n\tcmdSys          = 0xff\n\tcmdUnary uint16 = 50\n)\n"
  },
  {
    "path": "packages/script/code_block.go",
    "content": "package script\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n)\n\n/* Byte code could be described as a tree where functions and contracts are on the top level and\nnesting goes further according to nesting of bracketed. Tree nodes are structures of\n'CodeBlock' type. For instance,\n func a {\n\t if b {\n\t\t while d {\n\n\t\t }\n\t }\n\t if c {\n\t }\n }\n will be compiled into CodeBlock(a) which will have two child blocks CodeBlock (b) and CodeBlock (c) that\n are responsible for executing bytecode inside if. CodeBlock (b) will have a child CodeBlock (d) with\n a cycle.\n*/\n\n// CodeBlock contains all information about compiled block {...} and its children\ntype CodeBlock struct {\n\tObjects map[string]*ObjInfo\n\tType    ObjectType\n\tOwner   *OwnerInfo\n\t// Types that are valid to be assigned to Info:\n\t//\t*FuncInfo\n\t//\t*ContractInfo\n\tInfo     isCodeBlockInfo\n\tParent   *CodeBlock\n\tVars     []reflect.Type\n\tCode     ByteCodes\n\tChildren CodeBlocks\n}\n\ntype isCodeBlockInfo interface {\n\tisCodeBlockInfo()\n}\n\nfunc (*FuncInfo) isCodeBlockInfo()     {}\nfunc (*ContractInfo) isCodeBlockInfo() {}\n\nfunc (m *CodeBlock) GetInfo() isCodeBlockInfo {\n\tif m != nil {\n\t\treturn m.Info\n\t}\n\treturn nil\n}\n\nfunc (m *CodeBlock) GetFuncInfo() *FuncInfo {\n\tif x, ok := m.GetInfo().(*FuncInfo); ok {\n\t\treturn x\n\t}\n\treturn nil\n}\n\nfunc (m *CodeBlock) GetContractInfo() *ContractInfo {\n\tif x, ok := m.GetInfo().(*ContractInfo); ok {\n\t\treturn x\n\t}\n\treturn nil\n}\n\n// ByteCode stores a command and an additional parameter.\ntype ByteCode struct {\n\tCmd   uint16\n\tLine  uint16\n\tValue any\n}\n\n// CodeBlocks is a slice of blocks\ntype CodeBlocks []*CodeBlock\n\nfunc (bs *CodeBlocks) push(x any) {\n\t*bs = append(*bs, x.(*CodeBlock))\n}\n\nfunc (bs *CodeBlocks) peek() *CodeBlock {\n\tbsLen := len(*bs)\n\tif bsLen == 0 {\n\t\treturn nil\n\t}\n\treturn (*bs)[bsLen-1]\n}\n\nfunc (bs *CodeBlocks) get(idx int) *CodeBlock {\n\tif idx >= 0 && len(*bs) > 0 && len(*bs) > idx {\n\t\treturn (*bs)[idx]\n\t}\n\treturn nil\n}\n\n// ByteCodes is the slice of ByteCode items\ntype ByteCodes []*ByteCode\n\nfunc (bs *ByteCodes) push(x any) {\n\t*bs = append(*bs, x.(*ByteCode))\n}\n\nfunc (bs *ByteCodes) peek() *ByteCode {\n\tbsLen := len(*bs)\n\tif bsLen == 0 {\n\t\treturn nil\n\t}\n\treturn (*bs)[bsLen-1]\n}\n\nfunc newByteCode(cmd uint16, line uint16, value any) *ByteCode {\n\treturn &ByteCode{Cmd: cmd, Line: line, Value: value}\n}\n\n// OwnerInfo storing info about owner\ntype OwnerInfo struct {\n\tStateID  uint32 `json:\"state\"`\n\tActive   bool   `json:\"active\"`\n\tTableID  int64  `json:\"tableid\"`\n\tWalletID int64  `json:\"walletid\"`\n\tTokenID  int64  `json:\"tokenid\"`\n}\n\n// ObjInfo is the common object type\ntype ObjInfo struct {\n\tType ObjectType\n\t// Types that are valid to be assigned to Value:\n\t//\t*CodeBlock\n\t//\t*ExtFuncInfo\n\t//\t*ObjInfo_Variable\n\t//\t*ObjInfo_ExtendVariable\n\tValue isObjInfoValue\n}\n\ntype isObjInfoValue interface {\n\tisObjInfoValue()\n}\ntype ObjInfo_Variable struct {\n\tName  string\n\tIndex int\n}\ntype ObjInfo_ExtendVariable struct {\n\t//object extend variable name\n\tName string\n}\n\nfunc (*CodeBlock) isObjInfoValue()              {}\nfunc (*ExtFuncInfo) isObjInfoValue()            {}\nfunc (*ObjInfo_Variable) isObjInfoValue()       {}\nfunc (*ObjInfo_ExtendVariable) isObjInfoValue() {}\n\nfunc (m *ObjInfo) GetValue() isObjInfoValue {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\nfunc (m *ObjInfo) GetCodeBlock() *CodeBlock {\n\tif x, ok := m.GetValue().(*CodeBlock); ok {\n\t\treturn x\n\t}\n\treturn nil\n}\n\nfunc (m *ObjInfo) GetExtFuncInfo() *ExtFuncInfo {\n\tif x, ok := m.GetValue().(*ExtFuncInfo); ok {\n\t\treturn x\n\t}\n\treturn nil\n}\n\nfunc (m *ObjInfo) GetVariable() *ObjInfo_Variable {\n\tif x, ok := m.GetValue().(*ObjInfo_Variable); ok {\n\t\treturn x\n\t}\n\treturn nil\n}\n\nfunc (m *ObjInfo) GetExtendVariable() *ObjInfo_ExtendVariable {\n\tif x, ok := m.GetValue().(*ObjInfo_ExtendVariable); ok {\n\t\treturn x\n\t}\n\treturn nil\n}\n\nfunc NewCodeBlock() *CodeBlock {\n\tb := &CodeBlock{\n\t\tObjects: make(map[string]*ObjInfo),\n\t\t// Reserved 256 indexes for system purposes\n\t\tChildren: make(CodeBlocks, 256, 1024),\n\t}\n\tb.Extend(NewExtendData())\n\treturn b\n}\n\n// Extend sets the extended variables and functions\nfunc (b *CodeBlock) Extend(ext *ExtendData) {\n\tfor key, item := range ext.Objects {\n\t\tfobj := reflect.ValueOf(item).Type()\n\t\tswitch fobj.Kind() {\n\t\tcase reflect.Func:\n\t\t\t_, canWrite := ext.WriteFuncs[key]\n\t\t\tdata := &ExtFuncInfo{\n\t\t\t\tName:     key,\n\t\t\t\tParams:   make([]reflect.Type, fobj.NumIn()),\n\t\t\t\tResults:  make([]reflect.Type, fobj.NumOut()),\n\t\t\t\tAuto:     make([]string, fobj.NumIn()),\n\t\t\t\tVariadic: fobj.IsVariadic(),\n\t\t\t\tFunc:     item,\n\t\t\t\tCanWrite: canWrite}\n\t\t\tfor i := 0; i < fobj.NumIn(); i++ {\n\t\t\t\tif isauto, ok := ext.AutoPars[fobj.In(i).String()]; ok {\n\t\t\t\t\tdata.Auto[i] = isauto\n\t\t\t\t}\n\t\t\t\tdata.Params[i] = fobj.In(i)\n\t\t\t}\n\t\t\tfor i := 0; i < fobj.NumOut(); i++ {\n\t\t\t\tdata.Results[i] = fobj.Out(i)\n\t\t\t}\n\t\t\tb.Objects[key] = &ObjInfo{Type: ObjectType_ExtFunc, Value: data}\n\t\t}\n\t}\n}\n\nfunc (b *CodeBlock) getObjByNameExt(name string, state uint32) (ret *ObjInfo) {\n\tsname := StateName(state, name)\n\tif ret = b.getObjByName(name); ret == nil && len(sname) > 0 {\n\t\tret = b.getObjByName(sname)\n\t}\n\treturn\n}\n\nfunc (block *CodeBlock) getObjByName(name string) (ret *ObjInfo) {\n\tvar ok bool\n\tnames := strings.Split(name, `.`)\n\tfor i, name := range names {\n\t\tret, ok = block.Objects[name]\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tif i == len(names)-1 {\n\t\t\treturn\n\t\t}\n\t\tif ret.Type != ObjectType_Contract && ret.Type != ObjectType_Func {\n\t\t\treturn nil\n\t\t}\n\t\tblock = ret.GetCodeBlock()\n\t}\n\treturn\n}\n\nfunc (cb *CodeBlock) contractBaseCost() int64 {\n\tvar cost int64\n\tc := cb.GetContractInfo()\n\tif c != nil {\n\t\tcost += int64(len(cb.Objects) * CostCall)\n\t\tcost += int64(len(c.Settings) * CostCall)\n\t\tif c.Tx != nil {\n\t\t\tcost += int64(len(*c.Tx) * CostExtend)\n\t\t}\n\t}\n\treturn cost\n}\n\nfunc (block *CodeBlock) isParentContract() bool {\n\tif block.Parent != nil && block.Parent.Type == ObjectType_Contract {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc setWritable(block *CodeBlocks) {\n\tfor i := len(*block) - 1; i >= 0; i-- {\n\t\tblockItem := (*block)[i]\n\t\tif blockItem.Type == ObjectType_Func {\n\t\t\tblockItem.GetFuncInfo().CanWrite = true\n\t\t}\n\t\tif blockItem.Type == ObjectType_Contract {\n\t\t\tblockItem.GetContractInfo().CanWrite = true\n\t\t}\n\t}\n}\nfunc (ret *ObjInfo) getInParams() int {\n\tif ret.Type == ObjectType_ExtFunc {\n\t\treturn len(ret.GetExtFuncInfo().Params)\n\t}\n\treturn len(ret.GetCodeBlock().GetFuncInfo().Params)\n}\n"
  },
  {
    "path": "packages/script/compile.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// operPrior contains command and its priority\ntype operPrior struct {\n\tCmd      uint16 // identifier of the command\n\tPriority uint16 // priority of the command\n}\n\n// State contains a new state and a handle function\ntype compileState struct {\n\tNewState   stateTypes  // a new state\n\tFuncFlag   int         // a handle flag\n\tFuncHandle compileFunc // a handle function\n}\n\nfunc newCompileState(newState stateTypes, funcFlag int) compileState {\n\treturn compileState{NewState: newState, FuncFlag: funcFlag, FuncHandle: funcHandles[funcFlag]}\n}\n\nconst (\n\tmapConst = iota\n\tmapVar\n\tmapMap\n\tmapExtend\n\tmapArray\n\n\tmustKey\n\tmustColon\n\tmustComma\n\tmustValue\n)\n\ntype mapItem struct {\n\tType  int\n\tValue any\n}\n\n// The compiler converts the sequence of lexemes into the bytecodes using a finite state machine the same as\n// it was implemented in lexical analysis. The difference lays in that we do not convert the list of\n// states and transitions to the intermediate array.\n\nconst (\n\t// Errors of compilation\n\t//\terrNoError    = iota\n\terrUnknownCmd = iota + 1 // unknown command\n\terrMustName              // must be the name\n\terrMustLCurly            // must be '{'\n\terrMustRCurly            // must be '}'\n\terrParams                // wrong parameters\n\terrVars                  // wrong variables\n\terrVarType               // must be type\n\terrAssign                // must be '='\n\terrStrNum                // must be number or string\n)\n\nvar (\n\t// Array of operations and their priority\n\topers = map[uint32]operPrior{\n\t\tisOr:       {Cmd: cmdOr, Priority: 10},\n\t\tisAnd:      {Cmd: cmdAnd, Priority: 15},\n\t\tisEqEq:     {Cmd: cmdEqual, Priority: 20},\n\t\tisNotEq:    {Cmd: cmdNotEq, Priority: 20},\n\t\tisLess:     {Cmd: cmdLess, Priority: 22},\n\t\tisGrEq:     {Cmd: cmdNotLess, Priority: 22},\n\t\tisGreat:    {Cmd: cmdGreat, Priority: 22},\n\t\tisLessEq:   {Cmd: cmdNotGreat, Priority: 22},\n\t\tisPlus:     {Cmd: cmdAdd, Priority: 25},\n\t\tisMinus:    {Cmd: cmdSub, Priority: 25},\n\t\tisAsterisk: {Cmd: cmdMul, Priority: 30},\n\t\tisSolidus:  {Cmd: cmdDiv, Priority: 30},\n\t\tisSign:     {Cmd: cmdSign, Priority: cmdUnary},\n\t\tisNot:      {Cmd: cmdNot, Priority: cmdUnary},\n\t\tisLPar:     {Cmd: cmdSys, Priority: 0xff},\n\t\tisRPar:     {Cmd: cmdSys, Priority: 0},\n\t}\n)\n\n// StateName checks the name of the contract and modifies it to @[state]name if it is necessary.\nfunc StateName(state uint32, name string) string {\n\tif !strings.HasPrefix(name, `@`) {\n\t\treturn fmt.Sprintf(`@%d%s`, state, name)\n\t} else if len(name) > 1 && (name[1] < '0' || name[1] > '9') {\n\t\tname = `@1` + name[1:]\n\t}\n\treturn name\n}\n\n// CompileBlock compile the source code into the CodeBlock structure with a byte-code\nfunc (vm *VM) CompileBlock(input []rune, owner *OwnerInfo) (*CodeBlock, error) {\n\troot := &CodeBlock{Owner: owner}\n\tlexemes, err := lexParser(input)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(lexemes) == 0 {\n\t\treturn root, nil\n\t}\n\tcurState := stateRoot\n\tstack := make([]stateTypes, 0, 64)\n\tblockstack := make(CodeBlocks, 1, 64)\n\tblockstack[0] = root\n\tfork := 0\n\n\tfor i := 0; i < len(lexemes); i++ {\n\t\tvar (\n\t\t\tnewState compileState\n\t\t\tok       bool\n\t\t)\n\t\tlexeme := lexemes[i]\n\t\tif newState, ok = states[curState][int(lexeme.Type)]; !ok {\n\t\t\tnewState = states[curState][0]\n\t\t}\n\t\tnextState := newState.NewState & 0xff\n\t\tif (newState.NewState & stateFork) > 0 {\n\t\t\tfork = i\n\t\t}\n\t\tif (newState.NewState & stateToFork) > 0 {\n\t\t\ti = fork\n\t\t\tfork = 0\n\t\t\tlexeme = lexemes[i]\n\t\t}\n\n\t\tif (newState.NewState & stateStay) > 0 {\n\t\t\tcurState = nextState\n\t\t\ti--\n\t\t\tcontinue\n\t\t}\n\t\tif nextState == stateEval {\n\t\t\tif newState.NewState&stateLabel > 0 {\n\t\t\t\tblockstack.peek().Code.push(newByteCode(cmdLabel, lexeme.Line, 0))\n\t\t\t}\n\t\t\tcurlen := len(blockstack.peek().Code)\n\t\t\tif err := vm.compileEval(&lexemes, &i, &blockstack); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif (newState.NewState&stateMustEval) > 0 && curlen == len(blockstack.peek().Code) {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError}).Error(\"there is not eval expression\")\n\t\t\t\treturn nil, fmt.Errorf(\"there is not eval expression\")\n\t\t\t}\n\t\t\tnextState = curState\n\t\t}\n\t\tif (newState.NewState & statePush) > 0 {\n\t\t\tstack = append(stack, curState)\n\t\t\ttop := blockstack.peek()\n\t\t\tif top.Objects == nil {\n\t\t\t\ttop.Objects = make(map[string]*ObjInfo)\n\t\t\t}\n\t\t\tblock := &CodeBlock{Parent: top}\n\t\t\ttop.Children.push(block)\n\t\t\tblockstack.push(block)\n\t\t}\n\t\tif (newState.NewState & statePop) > 0 {\n\t\t\tif len(stack) == 0 {\n\t\t\t\treturn nil, fError(&blockstack, errMustLCurly, lexeme)\n\t\t\t}\n\t\t\tnextState = stack[len(stack)-1]\n\t\t\tstack = stack[:len(stack)-1]\n\n\t\t\tif len(blockstack) >= 2 {\n\t\t\t\tprev := blockstack.get(len(blockstack) - 2)\n\t\t\t\tif len(prev.Code) > 0 && (*prev).Code[len((*prev).Code)-1].Cmd == cmdContinue {\n\t\t\t\t\t(*prev).Code = (*prev).Code[:len((*prev).Code)-1]\n\t\t\t\t\tprev = blockstack.peek()\n\t\t\t\t\t(*prev).Code.push(newByteCode(cmdContinue, lexeme.Line, 0))\n\t\t\t\t}\n\t\t\t}\n\t\t\tblockstack = blockstack[:len(blockstack)-1]\n\t\t}\n\t\tif (newState.NewState & stateToBlock) > 0 {\n\t\t\tnextState = stateBlock\n\t\t}\n\t\tif (newState.NewState & stateToBody) > 0 {\n\t\t\tnextState = stateBody\n\t\t}\n\t\tif newState.FuncFlag > 0 {\n\t\t\tif err := funcHandles[newState.FuncFlag](&blockstack, nextState, lexeme); err != nil {\n\t\t\t\tlexeme.GetLogger().WithFields(log.Fields{\"type\": consts.ParseError, \"nextState\": nextState, \"flag\": newState.FuncFlag, \"err\": err, \"lex_value\": lexeme.Value}).Errorf(\"func handles\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tcurState = nextState\n\t}\n\tif len(stack) > 0 {\n\t\treturn nil, fError(&blockstack, errMustRCurly, lexemes[len(lexemes)-1])\n\t}\n\tfor _, item := range root.Objects {\n\t\tif item.Type == ObjectType_Contract {\n\t\t\tif cond, ok := item.GetCodeBlock().Objects[`conditions`]; ok {\n\t\t\t\tif cond.Type == ObjectType_Func && cond.GetCodeBlock().GetFuncInfo().CanWrite {\n\t\t\t\t\treturn nil, errCondWrite\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn root, nil\n}\n\n// FlushBlock loads the compiled CodeBlock into the virtual machine\nfunc (vm *VM) FlushBlock(root *CodeBlock) {\n\tshift := len(vm.Children)\n\tfor key, item := range root.Objects {\n\t\tif cur, ok := vm.Objects[key]; ok {\n\t\t\tswitch item.Type {\n\t\t\tcase ObjectType_Contract:\n\t\t\t\troot.Objects[key].GetCodeBlock().GetContractInfo().ID = cur.GetCodeBlock().GetContractInfo().ID + flushMark\n\t\t\tcase ObjectType_Func:\n\t\t\t\troot.Objects[key].GetCodeBlock().GetFuncInfo().ID = cur.GetCodeBlock().GetFuncInfo().ID + flushMark\n\t\t\t\tvm.Objects[key].Value = root.Objects[key].Value\n\t\t\t}\n\t\t}\n\t\tvm.Objects[key] = item\n\t}\n\tfor _, item := range root.Children {\n\t\tswitch item.Type {\n\t\tcase ObjectType_Contract:\n\t\t\tif item.GetContractInfo().ID > flushMark {\n\t\t\t\titem.GetContractInfo().ID -= flushMark\n\t\t\t\tvm.Children[item.GetContractInfo().ID] = item\n\t\t\t\tshift--\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\titem.Parent = vm.CodeBlock\n\t\t\titem.GetContractInfo().ID += uint32(shift)\n\t\tcase ObjectType_Func:\n\t\t\tif item.GetFuncInfo().ID > flushMark {\n\t\t\t\titem.GetFuncInfo().ID -= flushMark\n\t\t\t\tvm.Children[item.GetFuncInfo().ID] = item\n\t\t\t\tshift--\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\titem.Parent = vm.CodeBlock\n\t\t\titem.GetFuncInfo().ID += uint32(shift)\n\t\t}\n\t\tvm.Children = append(vm.Children, item)\n\t}\n}\n\n// FlushExtern switches off the extern mode of the compilation\nfunc (vm *VM) FlushExtern() {\n\tvm.Extern = false\n\treturn\n}\n\n// Compile compiles a source code and loads the byte-code into the virtual machine\nfunc (vm *VM) Compile(input []rune, owner *OwnerInfo) error {\n\troot, err := vm.CompileBlock(input, owner)\n\tif err == nil {\n\t\tvm.FlushBlock(root)\n\t}\n\treturn err\n}\n\nfunc findVar(name string, block *CodeBlocks) (ret *ObjInfo, owner *CodeBlock) {\n\tvar ok bool\n\ti := len(*block) - 1\n\tfor ; i >= 0; i-- {\n\t\tret, ok = (*block)[i].Objects[name]\n\t\tif ok {\n\t\t\treturn ret, (*block)[i]\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (vm *VM) findObj(name string, block *CodeBlocks) (ret *ObjInfo, owner *CodeBlock) {\n\tsname := StateName((*block)[0].Owner.StateID, name)\n\tret, owner = findVar(name, block)\n\tif ret != nil {\n\t\treturn\n\t} else if len(sname) > 0 {\n\t\tif ret, owner = findVar(sname, block); ret != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tif ret = vm.getObjByName(name); ret == nil && len(sname) > 0 {\n\t\tret = vm.getObjByName(sname)\n\t}\n\treturn\n}\n\nfunc (vm *VM) getInitValue(lexemes *Lexemes, ind *int, block *CodeBlocks) (value mapItem, err error) {\n\tvar (\n\t\tsubArr []mapItem\n\t\tsubMap *types.Map\n\t)\n\ti := *ind\n\tlexeme := (*lexemes)[i]\n\n\tswitch lexeme.Type {\n\tcase isLBrack:\n\t\tsubArr, err = vm.getInitArray(lexemes, &i, block)\n\t\tif err == nil {\n\t\t\tvalue = mapItem{Type: mapArray, Value: subArr}\n\t\t}\n\tcase isLCurly:\n\t\tsubMap, err = vm.getInitMap(lexemes, &i, block, false)\n\t\tif err == nil {\n\t\t\tvalue = mapItem{Type: mapMap, Value: subMap}\n\t\t}\n\tcase lexExtend:\n\t\tvalue = mapItem{Type: mapExtend, Value: lexeme.Value}\n\tcase lexIdent:\n\t\tobjInfo, tobj := vm.findObj(lexeme.Value.(string), block)\n\t\tif objInfo == nil {\n\t\t\terr = fmt.Errorf(eUnknownIdent, lexeme.Value)\n\t\t} else {\n\t\t\tvalue = mapItem{Type: mapVar, Value: &VarInfo{Obj: objInfo, Owner: tobj}}\n\t\t}\n\tcase lexNumber, lexString:\n\t\tvalue = mapItem{Type: mapConst, Value: lexeme.Value}\n\tdefault:\n\t\terr = errUnexpValue\n\t}\n\t*ind = i\n\treturn\n}\n\nfunc (vm *VM) getInitMap(lexemes *Lexemes, ind *int, block *CodeBlocks, oneItem bool) (*types.Map, error) {\n\tvar next int\n\tif !oneItem {\n\t\tnext = 1\n\t}\n\ti := *ind + next\n\tkey := ``\n\tret := types.NewMap()\n\tstate := mustKey\nmain:\n\tfor ; i < len(*lexemes); i++ {\n\t\tlexeme := (*lexemes)[i]\n\t\tswitch lexeme.Type {\n\t\tcase lexNewLine:\n\t\t\tcontinue\n\t\tcase isRCurly:\n\t\t\tbreak main\n\t\tcase isComma, isRBrack:\n\t\t\tif oneItem {\n\t\t\t\t*ind = i - 1\n\t\t\t\treturn ret, nil\n\t\t\t}\n\t\t}\n\t\tswitch state {\n\t\tcase mustComma:\n\t\t\tif lexeme.Type != isComma {\n\t\t\t\treturn nil, errUnexpComma\n\t\t\t}\n\t\t\tstate = mustKey\n\t\tcase mustColon:\n\t\t\tif lexeme.Type != isColon {\n\t\t\t\treturn nil, errUnexpColon\n\t\t\t}\n\t\t\tstate = mustValue\n\t\tcase mustKey:\n\t\t\tswitch lexeme.Type & 0xff {\n\t\t\tcase lexIdent, lexString:\n\t\t\t\tkey = lexeme.Value.(string)\n\t\t\tcase lexExtend:\n\t\t\t\tkey = `$` + lexeme.Value.(string)\n\t\t\tcase lexKeyword:\n\t\t\t\tfor ikey, v := range keywords {\n\t\t\t\t\tif fmt.Sprint(v) == fmt.Sprint(lexeme.Value) {\n\t\t\t\t\t\tkey = ikey\n\t\t\t\t\t\tif v == keyFunc && i < len(*lexemes)-1 && (*lexemes)[i+1].Type&0xff == lexIdent {\n\t\t\t\t\t\t\tcontinue main\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn nil, errUnexpKey\n\t\t\t}\n\t\t\tstate = mustColon\n\t\tcase mustValue:\n\t\t\tmapi, err := vm.getInitValue(lexemes, &i, block)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tret.Set(key, mapi)\n\t\t\tstate = mustComma\n\t\t}\n\t}\n\tif ret.IsEmpty() && state == mustKey {\n\t\treturn nil, errUnexpKey\n\t}\n\tif i == len(*lexemes) {\n\t\treturn nil, errUnclosedMap\n\t}\n\t*ind = i\n\treturn ret, nil\n}\n\nfunc (vm *VM) getInitArray(lexemes *Lexemes, ind *int, block *CodeBlocks) ([]mapItem, error) {\n\ti := *ind + 1\n\tret := make([]mapItem, 0)\n\tstate := mustValue\nmain:\n\tfor ; i < len(*lexemes); i++ {\n\t\tlexeme := (*lexemes)[i]\n\t\tswitch lexeme.Type {\n\t\tcase lexNewLine:\n\t\t\tcontinue\n\t\tcase isRBrack:\n\t\t\tbreak main\n\t\t}\n\t\tswitch state {\n\t\tcase mustComma:\n\t\t\tif lexeme.Type != isComma {\n\t\t\t\treturn nil, errUnexpComma\n\t\t\t}\n\t\t\tstate = mustValue\n\t\tcase mustValue:\n\t\t\tif i+1 < len(*lexemes) && (*lexemes)[i+1].Type == isColon {\n\t\t\t\tsubMap, err := vm.getInitMap(lexemes, &i, block, true)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tret = append(ret, mapItem{Type: mapMap, Value: subMap})\n\t\t\t} else {\n\t\t\t\tarri, err := vm.getInitValue(lexemes, &i, block)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tret = append(ret, arri)\n\t\t\t}\n\t\t\tstate = mustComma\n\t\t}\n\t}\n\tif len(ret) > 0 && state == mustValue {\n\t\treturn nil, errUnexpValue\n\t}\n\tif i == len(*lexemes) {\n\t\treturn nil, errUnclosedArray\n\t}\n\t*ind = i\n\treturn ret, nil\n}\n\n// This function is responsible for the compilation of expressions\nfunc (vm *VM) compileEval(lexemes *Lexemes, ind *int, block *CodeBlocks) error {\n\tvar indexInfo *IndexInfo\n\n\ti := *ind\n\tcurBlock := (*block)[len(*block)-1]\n\n\tbuffer := make(ByteCodes, 0, 20)\n\tbytecode := make(ByteCodes, 0, 100)\n\tparcount := make([]int, 0, 20)\n\tsetIndex := false\n\tnoMap := false\n\tprevLex := uint32(0)\nmain:\n\tfor ; i < len(*lexemes); i++ {\n\t\tvar cmd *ByteCode\n\t\tvar call bool\n\t\tlexeme := (*lexemes)[i]\n\t\tlogger := lexeme.GetLogger()\n\t\tif !noMap {\n\t\t\tif lexeme.Type == isLCurly {\n\t\t\t\tpMap, err := vm.getInitMap(lexemes, &i, block, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tbytecode.push(newByteCode(cmdMapInit, lexeme.Line, pMap))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif lexeme.Type == isLBrack {\n\t\t\t\tpArray, err := vm.getInitArray(lexemes, &i, block)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tbytecode.push(newByteCode(cmdArrayInit, lexeme.Line, pArray))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tnoMap = false\n\n\t\tswitch lexeme.Type {\n\t\tcase isRCurly, isLCurly:\n\t\t\ti--\n\t\t\tif prevLex == isComma || prevLex == lexOper {\n\t\t\t\treturn errEndExp\n\t\t\t}\n\t\t\tbreak main\n\t\tcase lexNewLine:\n\t\t\tif i > 0 && ((*lexemes)[i-1].Type == isComma || (*lexemes)[i-1].Type == lexOper) {\n\t\t\t\tcontinue main\n\t\t\t}\n\t\t\tfor k := len(buffer) - 1; k >= 0; k-- {\n\t\t\t\tif buffer[k].Cmd == cmdSys {\n\t\t\t\t\tcontinue main\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak main\n\t\tcase isLPar:\n\t\t\tbuffer.push(newByteCode(cmdSys, lexeme.Line, uint16(0xff)))\n\t\tcase isLBrack:\n\t\t\tbuffer.push(newByteCode(cmdSys, lexeme.Line, uint16(0xff)))\n\t\tcase isComma:\n\t\t\tif len(parcount) > 0 {\n\t\t\t\tparcount[len(parcount)-1]++\n\t\t\t}\n\t\t\tfor len(buffer) > 0 {\n\t\t\t\tprev := buffer[len(buffer)-1]\n\t\t\t\tif prev.Cmd == cmdSys && prev.Value.(uint16) == 0xff {\n\t\t\t\t\tbreak\n\t\t\t\t} else {\n\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\t}\n\t\t\t}\n\t\tcase isRPar:\n\t\t\tnoMap = true\n\t\t\tfor {\n\t\t\t\tif len(buffer) == 0 {\n\t\t\t\t\tlogger.WithFields(log.Fields{\"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"there is not pair\")\n\t\t\t\t\treturn fmt.Errorf(`there is not pair`)\n\t\t\t\t}\n\t\t\t\tprev := buffer[len(buffer)-1]\n\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\tif prev.Value.(uint16) == 0xff {\n\t\t\t\t\tbreak\n\t\t\t\t} else {\n\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(buffer) > 0 {\n\t\t\t\tif prev := buffer[len(buffer)-1]; prev.Cmd == cmdFuncName {\n\t\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\t\t(*prev).Value = FuncNameCmd{Name: prev.Value.(FuncNameCmd).Name,\n\t\t\t\t\t\tCount: parcount[len(parcount)-1]}\n\t\t\t\t\tparcount = parcount[:len(parcount)-1]\n\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t}\n\t\t\t\tvar tail *ByteCode\n\t\t\t\tif prev := buffer[len(buffer)-1]; prev.Cmd == cmdCall || prev.Cmd == cmdCallVariadic {\n\t\t\t\t\tobjInfo := prev.Value.(*ObjInfo)\n\t\t\t\t\tif (objInfo.Type == ObjectType_Func && objInfo.GetCodeBlock().GetFuncInfo().CanWrite) ||\n\t\t\t\t\t\t(objInfo.Type == ObjectType_ExtFunc && objInfo.GetExtFuncInfo().CanWrite) {\n\t\t\t\t\t\tsetWritable(block)\n\t\t\t\t\t}\n\t\t\t\t\tif objInfo.Type == ObjectType_Func && objInfo.GetCodeBlock().GetFuncInfo().Names != nil {\n\t\t\t\t\t\tif len(bytecode) == 0 || bytecode[len(bytecode)-1].Cmd != cmdFuncName {\n\t\t\t\t\t\t\tbytecode.push(newByteCode(cmdPush, lexeme.Line, nil))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif i < len(*lexemes)-4 && (*lexemes)[i+1].Type == isDot {\n\t\t\t\t\t\t\tif (*lexemes)[i+2].Type != lexIdent {\n\t\t\t\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError}).Error(\"must be the name of the tail\")\n\t\t\t\t\t\t\t\treturn fmt.Errorf(`must be the name of the tail`)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnames := prev.Value.(*ObjInfo).GetCodeBlock().GetFuncInfo().Names\n\t\t\t\t\t\t\tif _, ok := (*names)[(*lexemes)[i+2].Value.(string)]; !ok {\n\t\t\t\t\t\t\t\tif i < len(*lexemes)-5 && (*lexemes)[i+3].Type == isLPar {\n\t\t\t\t\t\t\t\t\tobjInfo, _ := vm.findObj((*lexemes)[i+2].Value.(string), block)\n\t\t\t\t\t\t\t\t\tif objInfo != nil && (objInfo.Type == ObjectType_Func || objInfo.Type == ObjectType_ExtFunc) {\n\t\t\t\t\t\t\t\t\t\ttail = newByteCode(uint16(cmdCall), lexeme.Line, objInfo)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif tail == nil {\n\t\t\t\t\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"tail\": (*lexemes)[i+2].Value.(string)}).Error(\"unknown function tail\")\n\t\t\t\t\t\t\t\t\treturn fmt.Errorf(`unknown function tail '%s'`, (*lexemes)[i+2].Value.(string))\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif tail == nil {\n\t\t\t\t\t\t\t\tbuffer.push(newByteCode(cmdFuncName, lexeme.Line, FuncNameCmd{Name: (*lexemes)[i+2].Value.(string)}))\n\t\t\t\t\t\t\t\tcount := 0\n\t\t\t\t\t\t\t\tif (*lexemes)[i+3].Type != isRPar {\n\t\t\t\t\t\t\t\t\tcount++\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tparcount = append(parcount, count)\n\t\t\t\t\t\t\t\ti += 2\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcount := parcount[len(parcount)-1]\n\t\t\t\t\tparcount = parcount[:len(parcount)-1]\n\t\t\t\t\tif prev.Value.(*ObjInfo).Type == ObjectType_ExtFunc {\n\t\t\t\t\t\tvar errtext string\n\t\t\t\t\t\textinfo := prev.Value.(*ObjInfo).GetExtFuncInfo()\n\t\t\t\t\t\twantlen := len(extinfo.Params)\n\t\t\t\t\t\tfor _, v := range extinfo.Auto {\n\t\t\t\t\t\t\tif len(v) > 0 {\n\t\t\t\t\t\t\t\twantlen--\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif count != wantlen && (!extinfo.Variadic || count < wantlen) {\n\t\t\t\t\t\t\terrtext = fmt.Sprintf(eWrongParams, extinfo.Name, wantlen)\n\t\t\t\t\t\t\tlogger.WithFields(log.Fields{\"error\": errtext, \"type\": consts.ParseError}).Error(errtext)\n\t\t\t\t\t\t\treturn fmt.Errorf(errtext)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif prev.Cmd == cmdCallVariadic {\n\t\t\t\t\t\tbytecode.push(newByteCode(cmdPush, lexeme.Line, count))\n\t\t\t\t\t}\n\t\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t\tif tail != nil {\n\t\t\t\t\t\tbuffer.push(tail)\n\t\t\t\t\t\tparcount = append(parcount, 1)\n\t\t\t\t\t\ti += 2\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase isRBrack:\n\t\t\tnoMap = true\n\t\t\tfor {\n\t\t\t\tif len(buffer) == 0 {\n\t\t\t\t\tlogger.WithFields(log.Fields{\"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"there is not pair\")\n\t\t\t\t\treturn fmt.Errorf(`there is not pair`)\n\t\t\t\t}\n\t\t\t\tprev := buffer[len(buffer)-1]\n\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\tif prev.Value.(uint16) == 0xff {\n\t\t\t\t\tbreak\n\t\t\t\t} else {\n\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(buffer) > 0 {\n\t\t\t\tif prev := buffer[len(buffer)-1]; prev.Cmd == cmdIndex {\n\t\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\t\tif i < len(*lexemes)-1 && (*lexemes)[i+1].Type == isEq {\n\t\t\t\t\t\ti++\n\t\t\t\t\t\tsetIndex = true\n\t\t\t\t\t\tindexInfo = prev.Value.(*IndexInfo)\n\t\t\t\t\t\tnoMap = false\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (*lexemes)[i+1].Type == isLBrack {\n\t\t\t\treturn errMultiIndex\n\t\t\t}\n\t\tcase lexOper:\n\t\t\tif oper, ok := opers[lexeme.Value.(uint32)]; ok {\n\t\t\t\tvar prevType uint32\n\t\t\t\tif i > 0 {\n\t\t\t\t\tprevType = (*lexemes)[i-1].Type\n\t\t\t\t}\n\t\t\t\tif oper.Cmd == cmdSub && (i == 0 || (prevType != lexNumber && prevType != lexIdent &&\n\t\t\t\t\tprevType != lexExtend && prevType != lexString && prevType != isRCurly &&\n\t\t\t\t\tprevType != isRBrack && prevType != isRPar)) {\n\t\t\t\t\toper.Cmd = cmdSign\n\t\t\t\t\toper.Priority = cmdUnary\n\t\t\t\t} else if prevLex == lexOper && oper.Priority != cmdUnary {\n\t\t\t\t\treturn errOper\n\t\t\t\t}\n\t\t\t\tbyteOper := newByteCode(oper.Cmd, lexeme.Line, oper.Priority)\n\n\t\t\t\tfor {\n\t\t\t\t\tif len(buffer) == 0 {\n\t\t\t\t\t\tbuffer.push(byteOper)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprev := buffer[len(buffer)-1]\n\t\t\t\t\t\tif prev.Value.(uint16) >= oper.Priority && oper.Priority != cmdUnary && prev.Cmd != cmdSys {\n\t\t\t\t\t\t\tif prev.Value.(uint16) == cmdUnary { // Right to left\n\t\t\t\t\t\t\t\tunar := len(buffer) - 1\n\t\t\t\t\t\t\t\tfor ; unar > 0 && buffer[unar-1].Value.(uint16) == cmdUnary; unar-- {\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbytecode = append(bytecode, buffer[unar:]...)\n\t\t\t\t\t\t\t\tbuffer = buffer[:unar]\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tbytecode.push(prev)\n\t\t\t\t\t\t\t\tbuffer = buffer[:len(buffer)-1]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbuffer.push(byteOper)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlogger.WithFields(log.Fields{\"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"unknown operator\")\n\t\t\t\treturn fmt.Errorf(`unknown operator %d`, lexeme.Value.(uint32))\n\t\t\t}\n\t\tcase lexNumber, lexString:\n\t\t\tnoMap = true\n\t\t\tcmd = newByteCode(cmdPush, lexeme.Line, lexeme.Value)\n\t\tcase lexExtend:\n\t\t\tnoMap = true\n\t\t\tif i < len(*lexemes)-2 {\n\t\t\t\tif (*lexemes)[i+1].Type == isLPar {\n\t\t\t\t\tcount := 0\n\t\t\t\t\tif (*lexemes)[i+2].Type != isRPar {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t\tparcount = append(parcount, count)\n\t\t\t\t\tbuffer.push(newByteCode(cmdCallExtend, lexeme.Line, lexeme.Value.(string)))\n\t\t\t\t\tcall = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !call {\n\t\t\t\tcmd = newByteCode(cmdExtend, lexeme.Line, lexeme.Value.(string))\n\t\t\t\tif i < len(*lexemes)-1 && (*lexemes)[i+1].Type == isLBrack {\n\t\t\t\t\tbuffer.push(newByteCode(cmdIndex, lexeme.Line, &IndexInfo{Extend: lexeme.Value.(string)}))\n\t\t\t\t}\n\t\t\t}\n\t\tcase lexIdent:\n\t\t\tnoMap = true\n\t\t\tobjInfo, tobj := vm.findObj(lexeme.Value.(string), block)\n\t\t\tif objInfo == nil && (!vm.Extern || i >= len(*lexemes)-2 || (*lexemes)[i+1].Type != isLPar) {\n\t\t\t\tlogger.WithFields(log.Fields{\"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"unknown identifier\")\n\t\t\t\treturn fmt.Errorf(eUnknownIdent, lexeme.Value)\n\t\t\t}\n\t\t\tif i < len(*lexemes)-2 {\n\t\t\t\tif (*lexemes)[i+1].Type == isLPar {\n\t\t\t\t\tvar (\n\t\t\t\t\t\tisContract  bool\n\t\t\t\t\t\tobjContract *CodeBlock\n\t\t\t\t\t)\n\t\t\t\t\tif vm.Extern && objInfo == nil {\n\t\t\t\t\t\tobjInfo = &ObjInfo{Type: ObjectType_Contract}\n\t\t\t\t\t}\n\t\t\t\t\tif objInfo == nil || (objInfo.Type != ObjectType_ExtFunc && objInfo.Type != ObjectType_Func &&\n\t\t\t\t\t\tobjInfo.Type != ObjectType_Contract) {\n\t\t\t\t\t\tlogger.WithFields(log.Fields{\"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"unknown function\")\n\t\t\t\t\t\treturn fmt.Errorf(`unknown function %s`, lexeme.Value.(string))\n\t\t\t\t\t}\n\t\t\t\t\tif objInfo.Type == ObjectType_Contract {\n\t\t\t\t\t\tif objInfo.Value != nil {\n\t\t\t\t\t\t\tobjContract = objInfo.GetCodeBlock()\n\t\t\t\t\t\t}\n\t\t\t\t\t\tobjInfo, tobj = vm.findObj(`ExecContract`, block)\n\t\t\t\t\t\tisContract = true\n\t\t\t\t\t}\n\t\t\t\t\tcmdCall := uint16(cmdCall)\n\t\t\t\t\tif (objInfo.Type == ObjectType_ExtFunc && objInfo.GetExtFuncInfo().Variadic) ||\n\t\t\t\t\t\t(objInfo.Type == ObjectType_Func && objInfo.GetCodeBlock().GetFuncInfo().Variadic) {\n\t\t\t\t\t\tcmdCall = cmdCallVariadic\n\t\t\t\t\t}\n\t\t\t\t\tcount := 0\n\t\t\t\t\tif (*lexemes)[i+2].Type != isRPar {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.push(newByteCode(cmdCall, lexeme.Line, objInfo))\n\t\t\t\t\tif isContract {\n\t\t\t\t\t\tname := StateName((*block)[0].Owner.StateID, lexeme.Value.(string))\n\t\t\t\t\t\tfor j := len(*block) - 1; j >= 0; j-- {\n\t\t\t\t\t\t\ttopblock := (*block)[j]\n\t\t\t\t\t\t\tif topblock.Type == ObjectType_Contract {\n\t\t\t\t\t\t\t\tif name == topblock.GetContractInfo().Name {\n\t\t\t\t\t\t\t\t\treturn errRecursion\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif topblock.GetContractInfo().Used == nil {\n\t\t\t\t\t\t\t\t\ttopblock.GetContractInfo().Used = make(map[string]bool)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttopblock.GetContractInfo().Used[name] = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif objContract != nil && objContract.GetContractInfo().CanWrite {\n\t\t\t\t\t\t\tsetWritable(block)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbytecode.push(newByteCode(cmdPush, lexeme.Line, name))\n\t\t\t\t\t\tif count == 0 {\n\t\t\t\t\t\t\tcount = 2\n\t\t\t\t\t\t\tbytecode.push(newByteCode(cmdPush, lexeme.Line, \"\"))\n\t\t\t\t\t\t\tbytecode.push(newByteCode(cmdPush, lexeme.Line, \"\"))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t\tif lexeme.Value.(string) == `CallContract` {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t\tbytecode.push(newByteCode(cmdPush, lexeme.Line, (*block)[0].Owner.StateID))\n\t\t\t\t\t}\n\t\t\t\t\tparcount = append(parcount, count)\n\t\t\t\t\tcall = true\n\t\t\t\t}\n\t\t\t\tif (*lexemes)[i+1].Type == isLBrack {\n\t\t\t\t\tif objInfo == nil || objInfo.Type != ObjectType_Var {\n\t\t\t\t\t\tlogger.WithFields(log.Fields{\"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"unknown variable\")\n\t\t\t\t\t\treturn fmt.Errorf(`unknown variable %s`, lexeme.Value.(string))\n\t\t\t\t\t}\n\t\t\t\t\tbuffer.push(newByteCode(cmdIndex, lexeme.Line, &IndexInfo{VarOffset: objInfo.GetVariable().Index, Owner: tobj}))\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !call {\n\t\t\t\tif objInfo.Type != ObjectType_Var {\n\t\t\t\t\treturn fmt.Errorf(`unknown variable %s`, lexeme.Value.(string))\n\t\t\t\t}\n\t\t\t\tcmd = newByteCode(cmdVar, lexeme.Line, &VarInfo{Obj: objInfo, Owner: tobj})\n\t\t\t}\n\t\t}\n\t\tif lexeme.Type != lexNewLine {\n\t\t\tprevLex = lexeme.Type\n\t\t}\n\t\tif lexeme.Type&0xff == lexKeyword {\n\t\t\tif lexeme.Value.(uint32) == keyTail {\n\t\t\t\tcmd = newByteCode(cmdUnwrapArr, lexeme.Line, 0)\n\t\t\t}\n\t\t}\n\t\tif cmd != nil {\n\t\t\tbytecode.push(cmd)\n\t\t}\n\t}\n\t*ind = i\n\tif prevLex == lexOper {\n\t\treturn errEndExp\n\t}\n\tfor i := len(buffer) - 1; i >= 0; i-- {\n\t\tif buffer[i].Cmd == cmdSys {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError}).Error(\"there is not pair\")\n\t\t\treturn fmt.Errorf(`there is not pair`)\n\t\t}\n\t\tbytecode.push(buffer[i])\n\t}\n\tif setIndex {\n\t\tbytecode.push(newByteCode(cmdSetIndex, 0, indexInfo))\n\t}\n\tcurBlock.Code = append(curBlock.Code, bytecode...)\n\treturn nil\n}\n\n// ContractsList returns list of contracts names from source of code\nfunc ContractsList(value string) ([]string, error) {\n\tnames := make([]string, 0)\n\tlexemes, err := lexParser([]rune(value))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"error\": err}).Error(\"getting contract list\")\n\t\treturn names, err\n\t}\n\tvar level int\n\tfor i, lexeme := range lexemes {\n\t\tswitch lexeme.Type {\n\t\tcase isLCurly:\n\t\t\tlevel++\n\t\tcase isRCurly:\n\t\t\tlevel--\n\t\tcase lexKeyword | (keyContract << 8), lexKeyword | (keyFunc << 8):\n\t\t\tif level == 0 && i+1 < len(lexemes) && lexemes[i+1].Type == lexIdent {\n\t\t\t\tnames = append(names, lexemes[i+1].Value.(string))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn names, nil\n}\n"
  },
  {
    "path": "packages/script/compile_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/shopspring/decimal\"\n)\n\ntype TestVM struct {\n\tInput  string\n\tFunc   string\n\tOutput any\n}\n\nfunc (block *CodeBlock) String() (ret string) {\n\tif (*block).Objects != nil {\n\t\tret = fmt.Sprintf(\"Objects: %v\\n\", (*block).Objects)\n\t}\n\tret += fmt.Sprintf(\"Type: %v \\n\", (*block).Type)\n\tif (*block).Children != nil {\n\t\tret += fmt.Sprintf(\"Blocks: [\\n\")\n\t\tfor i, item := range (*block).Children {\n\t\t\tret += fmt.Sprintf(\"{%d: %v}\\n\", i, item.String())\n\t\t}\n\t\tret += fmt.Sprintf(\"]\")\n\t}\n\treturn\n}\n\nfunc getMap() *types.Map {\n\tmyMap := types.NewMap()\n\tmyMap.Set(`par0`, `Parameter 0`)\n\tmyMap.Set(`par1`, `Parameter 1`)\n\treturn myMap\n}\n\nfunc getArray() []any {\n\tmyMap := types.NewMap()\n\tmyMap.Set(`par0`, `Parameter 0`)\n\tmyMap.Set(`par1`, `Parameter 1`)\n\treturn []any{myMap,\n\t\t\"The second string\", int64(2000)}\n}\n\n// Str converts the value to a string\nfunc str(v any) (ret string) {\n\treturn fmt.Sprint(v)\n}\n\nfunc lenArray(par []any) int64 {\n\treturn int64(len(par))\n}\n\nfunc Money(v any) (ret decimal.Decimal) {\n\tret, _ = ValueToDecimal(v)\n\treturn ret\n}\n\nfunc outMap(v *types.Map) string {\n\treturn fmt.Sprint(v)\n}\n\nfunc TestVMCompile(t *testing.T) {\n\ttest := []TestVM{\n\t\t{`contract sets {\n\t\t\tsettings {\n\t\t\t\tval = 1.56\n\t\t\t\trate = 100000000000\n\t\t\t\tname=\"Name parameter\"\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = Settings(\"@22sets\",\"name\")\n\t\t\t}\n\t\t}\n\t\tfunc result() string {\n\t\t\tvar par map\n\t\t\treturn CallContract(\"@22sets\", par) + \"=\" + sets()\n\t\t}\n\t\t`, `result`, `Name parameter=Name parameter`},\n\t\t{`func proc(par string) string {\n\t\t\t\t\treturn par + \"proc\"\n\t\t\t\t\t}\n\t\t\t\tfunc forarray string {\n\t\t\t\t\tvar my map\n\t\t\t\t\tvar ret array\n\t\t\t\t\tvar myret array\n\t\t\t\t\t\n\t\t\t\t\tret = GetArray()\n\t\t\t\t\tmyret[1] = \"Another \"\n\t\t\t\t\tmy = ret[0]\n\t\t\t\t\tmy[\"par3\"] = 3456\n\t\t\t\t\tret[2] = \"Test\"\n\t\t\t\t\treturn Sprintf(\"result=%s+%s+%d+%s\", ret[1], my[\"par0\"], my[\"par3\"], myret[1] + ret[2])\n\t\t\t\t}`, `forarray`, `result=The second string+Parameter 0+3456+Another Test`},\n\t\t{`func proc(par string) string {\n\t\t\t\treturn par + \"proc\"\n\t\t\t\t}\n\t\t\tfunc formap string {\n\t\t\t\tvar my map\n\t\t\t\tvar ret map\n\n\t\t\t\tret = GetMap()\n\t\t//\t\t\tPrintln(ret)\n\t\t\t\t//Println(\"Ooops\", ret[\"par0\"], ret[\"par1\"])\n\t\t\t\tmy[\"par1\"] = \"my value\" + proc(\" space \")\n\t\t\t\tmy[\"par2\"] = 203 * (100-86)\n\t\t\t\treturn Sprintf(\"result=%s+%d+%s+%s+%d\", ret[\"par1\"], my[\"par2\"] + 32, my[\"par1\"], proc($glob[\"test\"] ), $glob[\"number\"] )\n\t\t\t}`, `formap`, `result=Parameter 1+2874+my value space proc+String valueproc+1001`},\n\t\t{`func runtime string {\n\t\t\t\t\t\tvar i int\n\t\t\t\t\t\ti = 50\n\t\t\t\t\t\treturn Sprintf(\"val=%d\", i 0)\n\t\t\t\t\t}`, `runtime`, `runtime panic error,reflect: CallSlice using int64 as type string`},\n\t\t{`func nop {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfunc loop string {\n\t\t\t\t\t\t\tvar i int\n\t\t\t\t\t\t\twhile true {//i < 10 {\n\t\t\t\t\t\t\t\ti=i+1\n\t\t\t\t\t\t\t\tif i==5 {\n\t\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif i == 121 {\n\t\t\t\t\t\t\t\t\ti = i+ 4\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnop()\n\t\t\t\t\t\t\treturn Sprintf(\"val=%d\", i)\n\t\t\t\t\t\t}`, `loop`, `val=125`},\n\t\t{`contract my {\n\t\t\t\t\t\t\tdata {\n\t\t\t\t\t\t\t\tPar1 int\n\t\t\t\t\t\t\t\tPar2 string\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfunc conditions {\n\t\t\t\t\t\t\t\tvar q int\n\t\t\t\t\t\t\t\tPrintln(\"Front\", $Par1, $parent)\n\t\t\t\t//\t\t\t\tmy(\"Par1,Par2,ext\", 123, \"Parameter 2\", \"extended\" )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfunc action {\n\t\t\t\t\t\t\t\tPrintln(\"Main\", $Par2, $ext)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontract mytest {\n\t\t\t\t\t\t\tfunc init string {\n\t\t\t\t\t\t\t\tempty()\n\t\t\t\t\t\t\t\tmy(\"Par1,Par2,ext\", 123, \"Parameter 2\", \"extended\" )\n\t\t\t\t\t\t\t\t//my(\"Par1,Par2,ext\", 33123, \"Parameter 332\", \"33extended\" )\n\t\t\t\t\t\t\t\t//@26empty(\"test\",10)\n\t\t\t\t\t\t\t\tempty(\"toempty\", 10)\n\t\t\t\t\t\t\t\tPrintln( \"mytest\", $parent)\n\t\t\t\t\t\t\t\treturn \"OK INIT\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontract empty {\n\t\t\t\t\t\t\tconditions {Println(\"EmptyCond\")\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\taction {\n\t\t\t\t\t\t\t\tPrintln(\"Empty\", $parent)\n\t\t\t\t\t\t\t\tif 1 {\n\t\t\t\t\t\t\t\t\tmy(\"Par1,Par2,ext\", 123, \"Parameter 2\", \"extended\" )\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t`, `mytest.init`, `OK INIT`},\n\t\t{`func line_test string {\n\t\t\t\t\t\treturn \"Start \" +\n\t\t\t\t\t\tSprintf( \"My String %s %d %d\",\n\t\t\t\t\t\t\t\t\"Param 1\", 24,\n\t\t\t\t\t\t\t345 + 789)\n\t\t\t\t\t}`, `line_test`, `Start My String Param 1 24 1134`},\n\n\t\t{`func err_test string {\n\t\t\t\t\t\tif 1001.02 {\n\t\t\t\t\t\t\terror \"Error message err_test\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn \"OK\"\n\t\t\t\t\t}`, `err_test`, `{\"type\":\"error\",\"error\":\"Error message err_test\"}`},\n\t\t{`contract my {\n\t\t\t\t\tdata {\n\t\t\t\t\t\tPublicKey  bytes\n\t\t\t\t\t\tFirstName  string\n\t\t\t\t\t\tMiddleName string \"optional\"\n\t\t\t\t\t\tLastName   string\n\t\t\t\t\t}\n\t\t\t\t\tfunc init string {\n\t\t\t\t\t\treturn \"OK\"\n\t\t\t\t\t}\n\t\t\t\t}`, `my.init`, `OK`},\n\n\t\t{`func temp3 string {\n\t\t\t\t\t\tvar i1 i2 int, s1 string, s2 string\n\t\t\t\t\t\ti2, i1 = 348, 7\n\t\t\t\t\t\tif i1 > 5 {\n\t\t\t\t\t\t\tvar i5 int, s3 string\n\t\t\t\t\t\t\ti5 = 26788\n\t\t\t\t\t\t\ts1 = \"s1 string\"\n\t\t\t\t\t\t\ti2 = (i1+2)*i5+i2\n\t\t\t\t\t\t\ts2 = Sprintf(\"temp 3 function %s %d\", Sprintf(\"%s + %d\", s1, i2), -1 )\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn s2\n\t\t\t\t\t}`, `temp3`, `temp 3 function s1 string + 241440 -1`},\n\t\t{`func params2(myval int, mystr string ) string {\n\t\t\t\t\tif 101>myval {\n\t\t\t\t\t\tif myval == 90 {\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn Sprintf(\"myval=%d + %s\", myval, mystr )\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn \"OOPs\"\n\t\t\t\t}\n\t\t\t\tfunc temp2 string {\n\t\t\t\t\tif true {\n\t\t\t\t\t\treturn params2(51, \"Params 2 test\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t`, `temp2`, `myval=51 + Params 2 test`},\n\n\t\t{`func params(myval int, mystr string ) string {\n\t\t\t\t\treturn Sprintf(\"Params function %d %s\", 33 + myval + $test1, mystr + \" end\" )\n\t\t\t\t}\n\t\t\t\tfunc temp string {\n\t\t\t\t\treturn \"Prefix \" + params(20, \"Test string \" + $test2) + $test3( 202 )\n\t\t\t\t}\n\t\t\t\t`, `temp`, `Prefix Params function 154 Test string test 2 endtest=202=test`},\n\t\t{`func my_test string {\n\t\t\t\treturn Sprintf(\"Called my_test %s %d\", \"Ooops\", 777)\n\t\t\t}\n\n\tcontract my {\n\t\t\tfunc initf string {\n\t\t\t\treturn Sprintf(\"%d %s %s %s\", 65123 + (1001-500)*11, my_test(), \"Test message\", Sprintf(\"> %s %d <\",\"OK\", 999 ))\n\t\t\t}\n\t}`, `my.initf`, `70634 Called my_test Ooops 777 Test message > OK 999 <`},\n\t\t{`contract vars {\n\t\tfunc cond() string {return \"vars\"}\n\t\tfunc actions() { var test int}\n\t}`, `vars.cond`, `vars`},\n\t\t{`func mytail(name string, tail ...) string {\n\t\tif lenArray(tail) == 0 {\n\t\t\treturn name\n\t\t}\n\t\tif lenArray(tail) == 1 {\n\t\t\treturn Sprintf(\"%s=%v \", name, tail[0])\n\t\t}\n\t\treturn Sprintf(\"%s=%v+%v \", name, tail[1], tail[0])\n\t}\n\tfunc emptytail(tail ...) string {\n\t\treturn Sprintf(\"%d \", lenArray(tail))\n\t}\n\tfunc sum(out string, values ...) string {\n\t\tvar i, res int\n\t\twhile i < lenArray(values) {\n\t\t   res = res + values[i]\n\t\t   i = i+1\n\t\t}\n\t\treturn Sprintf(out, res)\n\t}\n\tfunc calltail() string {\n\t\tvar out string\n\t\tout = emptytail() + emptytail(10) + emptytail(\"name1\", \"name2\")\n\t\tout = out + mytail(\"OK\") + mytail(\"1=\", 11) + mytail(\"2=\", \"name\", 11)\n\t\treturn out + sum(\"Sum: %d\", 10, 20, 30, 40)\n\t}\n\t`, `calltail`, `0 1 2 OK1==11 2==11+name Sum: 100`},\n\t\t{`func DBFind( table string).Columns(columns string) \n\t\t. Where(format string, tail ...). Limit(limit int).\n\t\tOffset(offset int) string  {\n\t\tPrintln(\"DBFind\", table, tail)\n\t\treturn Sprintf(\"%s %s %s %d %d=\", table, columns, format, limit, offset)\n\t}\n\tfunc names() string {\n\t\tvar out, cols string\n\t\tcols = \"name,value\"\n\t\tout = DBFind( \"mytable\") + DBFind( \"keys\"\n\t\t\t).Columns(cols)+ DBFind( \"keys\"\n\t\t\t\t).Offset(199).Columns(\"qq\"+\"my\")\n\t\tout = out + DBFind( \"table\").Columns(\"name\").Where(\"id=?\", \n\t\t\t100).Limit(10) + DBFind( \"table\").Where(\"request\")\n\t\treturn out\n\t}`, `names`, `mytable   0 0=keys name,value  0 0=keys qqmy  0 199=table name id=? 10 0=table  request 0 0=`},\n\t\t{`contract seterr {\n\t\t\t\tfunc getset string {\n\t\t\t\t\tvar i int\n\t\t\t\t\ti = MyFunc(\"qqq\", 10)\n\t\t\t\t\treturn \"OK\"\n\t\t\t\t}\n\t\t\t}`, `seterr.getset`, `unknown identifier MyFunc`},\n\t\t{`func one() int {\n\t\t\t\treturn 9\n\t\t\t}\n\t\t\tfunc signfunc string {\n\t\t\t\tvar myarr array\n\t\t\t\tmyarr[0] = 0\n\t\t\t\tmyarr[1] = 1\n\t\t\t\tvar i, k, j int\n\t\t\t\tk = one()-2\n\t\t\t\tj = /*comment*/-3\n\t\t\t\ti = lenArray(myarr) - 1\n\t\t\t\treturn Sprintf(\"%s %d %d %d %d %d\", \"ok\", lenArray(myarr)-1, i, k, j, -4)\n\t\t\t}`, `signfunc`, `ok 1 1 7 -3 -4`},\n\t\t{`func exttest() string {\n\t\t\t\treturn Replace(\"text\", \"t\")\n\t\t\t}\n\t\t\t`, `exttest`, `function Replace must have 4 parameters`},\n\t\t{`func mytest(first string, second int) string {\n\t\t\t\treturn Sprintf(\"%s %d\", first, second)\n\t\t}\n\t\tfunc test() {\n\t\t\treturn mytest(\"one\", \"two\")\n\t\t}\n\t\t`, `test`, `parameter 2 has wrong type [:5]`},\n\t\t{`func mytest(first string, second int) string {\n\t\t\t\t\t\t\t\treturn Sprintf(\"%s %d\", first, second)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfunc test() string {\n\t\t\t\t\t\t\treturn mytest(\"one\")\n\t\t\t\t\t\t}\n\t\t\t\t\t\t`, `test`, `wrong count of parameters [:5]`},\n\t\t{\n\t\t\t`func ifMap string {\n\t\t\t\tvar m map\n\t\t\t\tif m {\n\t\t\t\t\treturn \"empty\"\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tm[\"test\"]=1\n\t\t\t\tif m {\n\t\t\t\t\treturn \"not empty\"\n\t\t\t\t}\n\n\t\t\t\treturn error \"error\"\n\t\t\t}`, \"ifMap\", \"not empty\",\n\t\t},\n\t\t{`func One(list array, name string) string {\n\t\t\tif list {\n\t\t\t\tvar row map \n\t\t\t\trow = list[0]\n\t\t\t\treturn row[name]\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tfunc Row(list array) map {\n\t\t\tvar ret map\n\t\t\tif list {\n\t\t\t\tret = list[0]\n\t\t\t}\n\t\t\treturn ret\n\t\t}\n\t\tfunc GetData().WhereId(id int) array {\n\t\t\tvar par array\n\t\t\tvar item map\n\t\t\titem[\"id\"] = str(id)\n\t\t\titem[\"name\"] = \"Test value \" + str(id)\n\t\t\tpar[0] = item\n\t\t\treturn par\n\t\t}\n\t\tfunc GetEmpty().WhereId(id int) array {\n\t\t\tvar par array\n\t\t\treturn par\n\t\t}\n\t\tfunc result() string {\n\t\t\tvar m map\n\t\t\tvar s string\n\t\t\tm = GetData().WhereId(123).Row()\n\t\t\ts = GetEmpty().WhereId(1).One(\"name\") \n\t\t\tif s != nil {\n\t\t\t\treturn \"problem\"\n\t\t\t}\n\t\t\treturn m[\"id\"] + \"=\" + GetData().WhereId(100).One(\"name\")\n\t\t}`, `result`, `123=Test value 100`},\n\t\t{`func mapbug() string {\n\t\t\t$data[10] = \"extend ok\"\n\t\t\treturn $data[10]\n\t\t\t}`, `mapbug`, `extend ok`},\n\t\t{`func result() string {\n\t\t\t\tvar myarr array\n\t\t\t\tmyarr[0] = \"string\"\n\t\t\t\tmyarr[1] = 7\n\t\t\t\tmyarr[2] = \"9th item\"\n\t\t\t\treturn Sprintf(\"RESULT=%s %d %v\", myarr...)\n\t\t\t}`, `result`, `RESULT=string 7 9th item`},\n\t\t{`func find().Where(pattern string, params ...) string {\n\t\t\t\treturn Sprintf(pattern, params ...)\n\t\t\t}\n\t\t\tfunc row().Where(pattern string, params ...) string {\n\t\t\t\treturn find().Where(pattern, params ...)\n\t\t\t}\n\t\t\tfunc result() string {\n\t\t\t\treturn row().Where(\"%d %d\", 10, 20)\n\t\t\t}\n\t\t\t`, `result`, `10 20`},\n\t\t{`func result string {\n\t\t\t\tvar arr array\n\t\t\t\tvar mymap map\n\t\t\t\tarr[100000] = 0\n\t\t\t\tvar i int\n\t\t\t\twhile i < 100 {\n\t\t\t\t\tmymap[str(i)] = 10\n\t\t\t\t\ti = i + 1\n\t\t\t\t}\n\t\t\t\ti = i + \"2\" \n\t\t\t\ti = (i - \"10\")/\"2\"*\"3\"\n\t\t\t\treturn Sprintf(\"%T %[1]v\", .21 + i)\n\t\t\t  }`, `result`, `float64 138.21`},\n\t\t{`func money_test string {\n\t\t\t\tvar my2, m1 money\n\t\t\t\tmy2 = 100\n\t\t\t\tm1 = 1.2\n\t\t\t\treturn Sprintf( \"Account %v %v %v\", my2/Money(3),  my2 - Money(5.6), m1*Money(5) + Money(my2))\n\t\t\t}`, `money_test`, `Account 33 95 105`},\n\t\t{`func long() int {\n\t\t\t\treturn  99999999999999999999\n\t\t\t\t}\n\t\t\t\tfunc result() string {\n\t\t\t\t\treturn Sprintf(\"ok=%d\", long())\n\t\t\t\t\t}`, `result`, `strconv.ParseInt: parsing \"99999999999999999999\": value out of range 99999999999999999999 [Ln:2 Col:34]`},\n\t\t{`func result() string {\n\t\t\tvar i, result int\n\t\t\t\n\t\t\tif true {\n\t\t\t\tif false {\n\t\t\t\t\tresult = 99\n\t\t\t\t} else {\n\t\t\t\t\tresult = 5\n\t\t\t\t}\n\t\t\t}\n\t\t\tif i == 1 {\n\t\t\t\tresult = 20\n\t\t\t} elif i> 0 {\n\t\t\t\tresult = 30\n\t\t\t} \n\t\t\telif i == 0 \n\t\t\t{\n\t\t\t\tresult = result + 50\n\t\t\t\tif true {\n\t\t\t\t\ti=10\n\t\t\t\t}\n\t\t\t} elif i==10 {\n\t\t\t\tPrintln(\"3\")\n\t\t\t\tresult = 0\n\t\t\t\ti=33\n\t\t\t} elif false {\n\t\t\t\tPrintln(\"4\")\n\t\t\t\tresult = 1\n\t\t\t} \n\t\t\telse \n\t\t\t{\n\t\t\t\tPrintln(\"5\")\n\t\t\t\tresult = 2\n\t\t\t}\n\t\t\tif i == 4 {\n\t\t\t\tresult = result\n\t\t\t} elif i == 20 {\n\t\t\t\tresult = 22\n\t\t\t} else {\n\t\t\t\tresult = result + 23\n\t\t\t\ti = 11\n\t\t\t}\n\t\t\tif i == 11 {\n\t\t\t\tresult = result + 7\n\t\t\t} else {\n\t\t\t\tresult = 0\n\t\t\t}\n\t\t\tif result == 85 {\n\t\t\t\tif false {\n\t\t\t\t\tresult = 1\n\t\t\t\t} elif 0 {\n\t\t\t\t\tresult = 5\n\t\t\t\t} elif 1 {\n\t\t\t\t\tresult = result + 10\n\t\t\t\t}\n\t\t\t}\n\t\t\tif result == 10 {\n\t\t\t\tresult = 11\n\t\t\t} elif result == 95 {\n\t\t\t\tresult = result + 1\n\t\t\t\tif false {\n\t\t\t\t\tresult = 0\n\t\t\t\t} elif true {\n\t\t\t\t\tresult = result + 4\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Sprintf(\"%d\", result)\n\t\t}\n\t\t`, `result`, `100`},\n\t\t{`func initerr string {\n\t\t\tvar my map\n\t\t\treturn {qqq\n\t\t`, `initerr`, `unclosed map initialization`},\n\t\t{`func initmap string {\n\t\t\tvar my, sub map\n\t\t\tvar list array\n\t\t\tvar i int\n\t\t\ti = 256\n\t\t\tvar s string\n\t\t\t$ext = \"Ooops\"\n\t\t\ts = \"Spain\"\n\t\t\tmy = {conditions: \"$Conditions\"}\n\t\t\tlist = [0, i, {\"item\": i}, [$ext]]\n\t\t\tsub = {\"name\": \"John\", \"lastname\": \"Smith\", myarr: []}\n\t\t\tmy = {qqq: 10, \"22\": \"MY STRING\", /* comment*/ \"float\": 1.2, \"ext\": $ext,\n\t\t\t\"in\": true, \"var\": i, sub: sub, \"Company\": {\"Name\": \"Ltd\", Country: s, \n\t\t\t\tArr: [s, 20, \"finish\"]}}\n\t\t\treturn outMap(my) + Sprintf(\"%v\", list)\n\t\t}`, `initmap`, `map[qqq:10 22:MY STRING float:1.2 ext:Ooops in:true var:256 sub:map[name:John lastname:Smith myarr:[]] Company:map[Name:Ltd Country:Spain Arr:[Spain 20 finish]]][0 256 map[item:256] [Ooops]]`},\n\t\t{`func test() string {\n\t\t\tvar where map\n\t\t\twhere[\"name\"] = {\"$in\": \"menus_names\"}\n\t\t\treturn Sprintf(\"%v\", where)\n\t\t }`, `test`, `map[name:map[$in:menus_names]]`},\n\t\t{`contract TestCyr {\n\t\t\tdata {}\n\t\t\tconditions { }\n\t\t\taction {\n\t\t\t   //test\n\t\t\t   var a map\n\t\t\t   a[\"test\"] = \"test\"\n\t\t\t   $result = a[\"test\"]\n\t\t\t}\n\t\t}\n\t\tfunc result() string {\n\t\t\tvar par map\n\t\t\treturn CallContract(\"TestCyr\", par) \n\t\t}`, `result`, `test`},\n\t\t{`contract MainCond {\n\t\t\tconditions {\n\t\t\t\terror $test\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = \"OK\"\n\t\t\t}\n\t\t}\n\t\tfunc result() bool {\n\t\t\treturn MainCond\n\t\t}\n\t\t`, `result`, `unknown variable MainCond`},\n\t\t{`func myFunc(my string) string {\n\t\t\treturn Sprintf(\"writable: %s\", my)\n\t\t}\n\t\tcontract mySet {\n\t\t\tconditions {\n\t\t\t\tmyFunc(\"test\")\t\n\t\t\t}\n\t\t\taction {\n\t\t\t\tmyFunc(\"test\")\t\n\t\t\t}\n\t\t}\t\n\t\tcontract myExec {\n\t\t\tconditions {\n\t\t\t\tmySet()\n\t\t\t}\n\t\t\taction {\n\t\t\t\tmySet()\n\t\t\t\t$result = \"OK\"\n\t\t\t}\n\t\t}\n\t\tfunc result() string {\n\t\t\tmyExec()\n\t\t\treturn \"COND\"\n\t\t}`, `result`, `'conditions' cannot call contracts or functions which can modify the blockchain database.`},\n\t\t{`func test string {\n\t\t\tvar s string\n\t\t\tvar m map\n\t\t\tm = {f: 5, b: 2, a: 1, d: 3, c: 0, e: 4}\n\t\t\tvar i int\n\t\t\twhile i<3{\n\t\t\t\ts = s + Sprintf(\"%v\", m)\n\t\t\t\ti = i + 1\n\t\t\t}\n\t\t\treturn s\n\t\t}\n\t\t`, `test`, `map[f:5 b:2 a:1 d:3 c:0 e:4]map[f:5 b:2 a:1 d:3 c:0 e:4]map[f:5 b:2 a:1 d:3 c:0 e:4]`},\n\t\t{`contract qqq3 {\n\t\t\tdata {\n\t\t\t\tName string \"aaq\"\n\t\t\t\tTemp\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = $Name\n\t\t\t}\n\t\t}\n\t\t`, `qqq3.action`, `expecting type of the data field [Ln:5 Col:1]`},\n\t\t{`contract qqq2 {\n\t\t\tdata {\n\t\t\t\tName string \"aaq\"\n\t\t\t\t\"awede\"\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = $Name\n\t\t\t}\n\t\t}\n\t\t`, `qqq2.action`, `unexpected tag [Ln:4 Col:6]`},\n\t\t{`contract qqq1 {\n\t\t\tdata {\n\t\t\t\tstring Name qwerty\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = $Name\n\t\t\t}\n\t\t}\n\t\t`, `qqq1.action`, `expecting name of the data field [Ln:3 Col:6]`},\n\t\t{`contract qqq {\n\t\t\tdata {\n\t\t\t\tName qwerty\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = $Name\n\t\t\t}\n\t\t}\n\t\t`, `qqq.action`, `expecting type of the data field [Ln:3 Col:11]`},\n\t\t{`contract qq3 {\n\t\t\tdata {\n\t\t\t\tId uint\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = \"OK\"\n\t\t\t}\n\t\t}\n\t\t`, `qq3.action`, `expecting type of the data field [Ln:3 Col:9]`},\n\t\t{`contract qq2 {\n\t\t\tdata {\n\t\t\t\tId, ID2 int\n\t\t\t}\n\t\t\taction {\n\t\t\t\t$result = str($Id) + str($ID2)\n\t\t\t}\n\t\t}\n\t\tfunc getqq() string {\n\t\t\treturn qq2(\"Id,ID2\", 10,20)\n\t\t}`, `getqq`, `1020`},\n\t\t{`func IND() string {\n\t\t\tvar a,b,d array\n\t\t\ta[0] = 100\n\t\t\ta[1] = 555\n\t\t\tb[0] = 200\n\t\t\td[0] = a\n\t\t\td[1] = b\n\t\t\td[0][0] =  777\n\t}`, `IND`, `multi-index is not supported`},\n\t\t{`func result() {\n\t\t/*\n\t\taa\n\t\t/*bb*/\n\t\t\n\t\terror \"test\"*/\n\t\t}`, `result`, `unexpected operator; expecting operand`},\n\t\t{`func result() {\n\t\t\t\terror \"test\"*\n\t\t\t\t}`, `result`, `unexpected end of the expression`},\n\t\t{`func bool_test string {\n\t\t\t\t\tvar i bool\n\t\t\t\t\tvar k bool\n\t\t\t\t\tvar out string\n\t\t\t\t\ti = true\n\t\t\t\t\tif i == true {\n\t\t\t\t\t\tout = \"OK\"\n\t\t\t\t\t}\n\t\t\t\t\tif i != k {\n\t\t\t\t\t\tout = out + \"ok\"\n\t\t\t\t\t}\n\t\t\t\t\tif i {\n\t\t\t\t\t\tout = out + \"I\"\n\t\t\t\t\t}\n\t\t\t\t\treturn out\n\t\t\t\t}`, `bool_test`, `OKokI`},\n\t}\n\tvm := NewVM()\n\tvm.Extern = true\n\tvm.Extend(&ExtendData{map[string]any{\"Println\": fmt.Println, \"Sprintf\": fmt.Sprintf,\n\t\t\"GetMap\": getMap, \"GetArray\": getArray, \"lenArray\": lenArray, \"outMap\": outMap,\n\t\t\"str\": str, \"Money\": Money, \"Replace\": strings.Replace}, nil,\n\t\tmap[string]struct{}{\"Sprintf\": {}}})\n\n\tfor ikey, item := range test {\n\t\tif ikey > 100 {\n\t\t\tbreak\n\t\t}\n\t\tsource := []rune(item.Input)\n\t\tif err := vm.Compile(source, &OwnerInfo{StateID: uint32(ikey) + 22, Active: true, TableID: 1}); err != nil {\n\t\t\tif err.Error() != item.Output {\n\t\t\t\tt.Errorf(`%s != %s`, err, item.Output)\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else {\n\t\t\tglob := types.NewMap()\n\t\t\tglob.Set(`test`, `String value`)\n\t\t\tglob.Set(`number`, 1001)\n\t\t\tif out, err := vm.Call(item.Func, nil, map[string]any{\n\t\t\t\t`rt_state`: uint32(ikey) + 22, `data`: make([]any, 0),\n\t\t\t\t`test1`: 101, `test2`: `test 2`,\n\t\t\t\t\"glob\": glob,\n\t\t\t\t`test3`: func(param int64) string {\n\t\t\t\t\treturn fmt.Sprintf(\"test=%d=test\", param)\n\t\t\t\t},\n\t\t\t}); err == nil {\n\t\t\t\tif out[0].(string) != item.Output {\n\t\t\t\t\tt.Error(fmt.Errorf(\"err want to %v, but out %v\\n\", item.Output, out[0]))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else if err.Error() != item.Output {\n\t\t\t\tt.Error(err)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t}\n\t}\n}\n\nfunc TestContractList(t *testing.T) {\n\ttest := []TestLexeme{{`contract NewContract {\n\t\tconditions {\n\t\t\tValidateCondition($Conditions,$ecosystem_id)\n\t\t\twhile i < Len(list) {\n\t\t\t\tif IsObject(list[i], $ecosystem_id) {\n\t\t\t\t\twarning Sprintf(\"Contract or function %s exists\", list[i] )\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\taction {\n\t\t}\n\t\tfunc price() int {\n\t\t\treturn  SysParamInt(\"price_create_contract\")\n\t\t}\n\t}func MyFunc {}`,\n\t\t`NewContract,MyFunc`},\n\t\t{`contract demo_contract {\n\t\t\tdata {\n\t\t\t\tcontract_txt str\n\t\t\t}\n\t\t\tfunc test() {\n\t\t\t}\n\t\t\tconditions {\n\t\t\t\tif $contract_txt=\"\" {\n\t\t\t\t\twarning \"Sorry, you do not have contract access to this action.\"\n\t\t\t\t}\n\t\t\t}\n\t\t} contract another_contract {} func main { func subfunc(){}}`,\n\t\t\t`demo_contract,another_contract,main`},\n\t}\n\tfor _, item := range test {\n\t\tlist, _ := ContractsList(item.Input)\n\t\tif strings.Join(list, `,`) != item.Output {\n\t\t\tt.Error(`wrong names`, strings.Join(list, `,`))\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc TestVM_CompileBlock(t *testing.T) {\n\tr := []rune(`\n\t\tcontract aaa {\n\t\t\tdata { \n\t\t\t\tkey_id int\n\t\t\t\t//time string\n\t\t\t}\n\t\t\tfunc bbb(account_id int){\n\t\t\t\t//$key_id = 2\n\t\t\t\taccount_id = 3\n\t\t\t}\n\t\t\tconditions {\n\t\t\t\t//$key_id = 3\n  \t\t\t}\n\t\t\taction {\n\t\t\t}\n\t\t}\n`)\n\ttype args struct {\n\t\tinput []rune\n\t\towner *OwnerInfo\n\t}\n\tvm := NewVM()\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twant    *CodeBlock\n\t\twantErr assert.ErrorAssertionFunc\n\t}{\n\t\t{name: \"collides\", args: args{\n\t\t\tr, &OwnerInfo{StateID: 1},\n\t\t}, wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {\n\t\t\tif err != nil {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t}},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := vm.CompileBlock(tt.args.input, tt.args.owner)\n\t\t\tif !tt.wantErr(t, err, fmt.Sprintf(\"CompileBlock(%v, %v)\", tt.args.input, tt.args.owner)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.Equalf(t, tt.want, got, \"CompileBlock(%v, %v)\", tt.args.input, tt.args.owner)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "packages/script/errors.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport \"errors\"\n\nconst (\n\teContractLoop         = `there is loop in %s contract`\n\teSysVar               = `system variable $%s cannot be changed`\n\teSysFunc              = `system function '%s' cannot be changed`\n\teDataParamVarCollides = `param variable '%s' in the data section of the contract '%s' collides with the 'builtin' variable`\n\teTypeParam            = `parameter %d has wrong type`\n\teUndefinedParam       = `%s is not defined`\n\teUnknownContract      = `unknown contract %s`\n\teWrongParams          = `function %s must have %d parameters`\n\teArrIndex             = `index of array cannot be type %s`\n\teMapIndex             = `index of map cannot be type %s`\n\teUnknownIdent         = `unknown identifier %s`\n\teWrongVar             = `wrong var %v`\n\teDataType             = `expecting type of the data field [Ln:%d Col:%d]`\n\teDataName             = `expecting name of the data field [Ln:%d Col:%d]`\n\teDataTag              = `unexpected tag [Ln:%d Col:%d]`\n\teConditionNotAllowed  = `condition %s is not allowed`\n)\n\nvar (\n\terrContractPars       = errors.New(`wrong contract parameters`)\n\terrWrongCountPars     = errors.New(`wrong count of parameters`)\n\terrDivZero            = errors.New(`divided by zero`)\n\terrUnsupportedType    = errors.New(`unsupported combination of types in the operator`)\n\terrMaxArrayIndex      = errors.New(`the index is out of range`)\n\terrMaxMapCount        = errors.New(`the maxumim length of map`)\n\terrRecursion          = errors.New(`the contract can't call itself recursively`)\n\terrUnclosedArray      = errors.New(`unclosed array initialization`)\n\terrUnclosedMap        = errors.New(`unclosed map initialization`)\n\terrUnexpKey           = errors.New(`unexpected lexeme; expecting string key`)\n\terrUnexpColon         = errors.New(`unexpected lexeme; expecting colon`)\n\terrUnexpComma         = errors.New(`unexpected lexeme; expecting comma`)\n\terrUnexpValue         = errors.New(`unexpected lexeme; expecting string, int value or variable`)\n\terrCondWrite          = errors.New(`'conditions' cannot call contracts or functions which can modify the blockchain database`)\n\terrMultiIndex         = errors.New(`multi-index is not supported`)\n\terrSelfAssignment     = errors.New(`self assignment`)\n\terrEndExp             = errors.New(`unexpected end of the expression`)\n\terrOper               = errors.New(`unexpected operator; expecting operand`)\n\terrIncorrectParameter = errors.New(`incorrect parameter of the condition function`)\n)\n"
  },
  {
    "path": "packages/script/eval.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype evalCode struct {\n\tSource string\n\tCode   *CodeBlock\n}\n\nvar (\n\tevals = make(map[uint64]*evalCode)\n)\n\n// CompileEval compiles conditional expression\nfunc (vm *VM) CompileEval(input string, state uint32) error {\n\tsource := `func eval bool { return ` + input + `}`\n\tif input == `1` || input == `0` {\n\t\tsource = `\n\t\tfunc eval bool { \n\t\t\tif ` + input + ` == 1 {\n\t\t\t\treturn true\n\t\t\t} else {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}`\n\t}\n\n\tblock, err := vm.CompileBlock([]rune(source), &OwnerInfo{StateID: state})\n\tif err != nil {\n\t\treturn err\n\t}\n\tcrc := crypto.CalcChecksum([]byte(input))\n\tevals[crc] = &evalCode{Source: input, Code: block}\n\treturn nil\n}\n\n// EvalIf runs the conditional expression. It compiles the source code before that if that's necessary.\nfunc (vm *VM) EvalIf(input string, state uint32, vars map[string]any) (bool, error) {\n\tif len(input) == 0 {\n\t\treturn true, nil\n\t}\n\tcrc := crypto.CalcChecksum([]byte(input))\n\tif eval, ok := evals[crc]; !ok || eval.Source != input {\n\t\tif err := vm.CompileEval(input, state); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.EvalError, \"error\": err}).Error(\"compiling eval\")\n\t\t\treturn false, err\n\t\t}\n\t}\n\tret, err := NewRunTime(vm, syspar.GetMaxCost()).Run(evals[crc].Code.Children[0], nil, vars)\n\tif err == nil {\n\t\tif len(ret) == 0 {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn valueToBool(ret[0]), nil\n\t}\n\treturn false, err\n}\n"
  },
  {
    "path": "packages/script/eval_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\ntype TestComp struct {\n\tInput  string\n\tOutput string\n}\n\nfunc Multi(a, b int64) (int64, error) {\n\treturn a + b*2, nil\n}\n\nfunc TestEvalIf(t *testing.T) {\n\ttest := []TestComp{\n\t\t{`Multi(45, $citizenId\")`, `there is not pair`},\n\t\t{\"34 + `45` < 0\", `runtime panic error`},\n\t\t{\"Multi( (34+35)*2, Multi( $citizenId, 56))== 1 || Multi( (34+35)*2, Multi( $citizenId, 56))== 0\", `false`},\n\t\t{\"5 + 9 > 10\", `true`},\n\t\t{\"34 == 45\", `false`},\n\t\t{\"1345\", `true`},\n\t\t{\"13/13-1\", `false`},\n\t\t{\"7665 > ($citizenId-48000)\", \"false\"},\n\t\t{\"56788 + 1 >= $citizenId\", \"true\"},\n\t\t{\"76 < $citizenId\", \"true\"},\n\t\t{\"56789 <= $citizenId\", \"true\"},\n\t\t{\"56 == 56\", \"true\"},\n\t\t{\"37 != 37\", \"false\"},\n\t\t{\"!!(1-1)\", \"false\"},\n\t\t{\"!!$citizenId || $wallet_id\", \"true\"},\n\t\t{\"!789\", \"false\"},\n\t\t{\"$citizenId == 56780 + 9\", `true`},\n\t\t{\"qwerty(45)\", `unknown identifier qwerty`},\n\t\t{\"Multi(2, 5) > 36\", \"false\"},\n\t\t{\"789 63 == 63\", \"true\"},\n\t\t{\"+421\", \"stack is empty\"},\n\t\t{\"1256778+223445==1480223\", \"true\"},\n\t\t{\"(67-34789)*3 == -104166\", \"true\"},\n\t\t{\"(5+78)*(1563-527) == 85988\", \"true\"},\n\t\t{\"124 * (143-527\", \"there is not pair\"},\n\t\t{\"341 * 234/0\", \"divided by zero\"},\n\t\t{\"0 == ((15+82)*2 + 5)/2 - 99\", \"true\"},\n\t\t{\"Multi( (34+35)*2, Multi( $citizenId, 56))== 1 || Multi( (34+35)*2, Multi( $citizenId, 56))== 0\", `false`},\n\t\t{\"2+ Multi( (34+35)*2, Multi( $citizenId, 56)) /2 == 56972\", `true`},\n\t\t{\"$citizenId && 0\", \"false\"},\n\t\t{\"0|| ($citizenId + $wallet_id == 950240)\", \"true\"},\n\t}\n\tvars := map[string]any{\n\t\t`citizenId`: 56789,\n\t\t`wallet_id`: 893451,\n\t}\n\tvm := NewVM()\n\tvm.Extend(&ExtendData{map[string]any{\"Multi\": Multi}, nil, nil})\n\tfor _, item := range test {\n\t\tout, err := vm.EvalIf(item.Input, 0, vars)\n\t\tif err != nil {\n\t\t\tif err.Error() != item.Output {\n\t\t\t\tt.Error(`error of ifeval ` + item.Input + ` ` + err.Error())\n\t\t\t}\n\t\t} else {\n\t\t\tif fmt.Sprint(out) != item.Output {\n\t\t\t\tt.Error(`error of ifeval ` + item.Input + ` Output:` + fmt.Sprint(out))\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/script/extend.go",
    "content": "package script\n\nconst (\n\tExtend_type                = `type`\n\tExtend_time                = `time`\n\tExtend_ecosystem_id        = `ecosystem_id`\n\tExtend_node_position       = `node_position`\n\tExtend_block               = `block`\n\tExtend_key_id              = `key_id`\n\tExtend_account_id          = `account_id`\n\tExtend_block_key_id        = `block_key_id`\n\tExtend_parent              = `parent`\n\tExtend_txcost              = `txcost`\n\tExtend_txhash              = `txhash`\n\tExtend_result              = `result`\n\tExtend_sc                  = `sc`\n\tExtend_contract            = `contract`\n\tExtend_block_time          = `block_time`\n\tExtend_original_contract   = `original_contract`\n\tExtend_this_contract       = `this_contract`\n\tExtend_guest_key           = `guest_key`\n\tExtend_guest_account       = `guest_account`\n\tExtend_black_hole_key      = `black_hole_key`\n\tExtend_black_hole_account  = `black_hole_account`\n\tExtend_white_hole_key      = `white_hole_key`\n\tExtend_white_hole_account  = `white_hole_account`\n\tExtend_pre_block_data_hash = `pre_block_data_hash`\n\tExtend_gen_block           = `gen_block`\n\tExtend_time_limit          = `time_limit`\n\n\tExtend_rt_state = `rt_state`\n\tExtend_rt       = `rt`\n\tExtend_stack    = `stack`\n\tExtend_loop     = `loop_`\n)\nconst (\n\t// system variable cannot be changed\n\tsysVars_block               = `block`\n\tsysVars_block_key_id        = `block_key_id`\n\tsysVars_block_time          = `block_time`\n\tsysVars_data                = `data`\n\tsysVars_ecosystem_id        = `ecosystem_id`\n\tsysVars_key_id              = `key_id`\n\tsysVars_account_id          = `account_id`\n\tsysVars_node_position       = `node_position`\n\tsysVars_parent              = `parent`\n\tsysVars_original_contract   = `original_contract`\n\tsysVars_sc                  = `sc`\n\tsysVars_contract            = `contract`\n\tsysVars_stack               = `stack`\n\tsysVars_this_contract       = `this_contract`\n\tsysVars_time                = `time`\n\tsysVars_type                = `type`\n\tsysVars_txcost              = `txcost`\n\tsysVars_txhash              = `txhash`\n\tsysVars_guest_key           = `guest_key`\n\tsysVars_guest_account       = `guest_account`\n\tsysVars_black_hole_key      = `black_hole_key`\n\tsysVars_white_hole_key      = `white_hole_key`\n\tsysVars_black_hole_account  = `black_hole_account`\n\tsysVars_white_hole_account  = `white_hole_account`\n\tsysVars_gen_block           = `gen_block`\n\tsysVars_time_limit          = `time_limit`\n\tsysVars_pre_block_data_hash = `pre_block_data_hash`\n)\n"
  },
  {
    "path": "packages/script/func.go",
    "content": "package script\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// ExtendData is used for the definition of the extended functions and variables\ntype ExtendData struct {\n\tObjects    map[string]any\n\tAutoPars   map[string]string\n\tWriteFuncs map[string]struct{}\n}\n\nfunc NewExtendData() *ExtendData {\n\treturn &ExtendData{\n\t\tObjects: map[string]any{\n\t\t\t\"ExecContract\": ExecContract,\n\t\t\t\"CallContract\": ExContract,\n\t\t\t\"Settings\":     GetSettings,\n\t\t\t\"MemoryUsage\":  MemoryUsage,\n\t\t\t\"Println\":      fmt.Println,\n\t\t\t\"Sprintf\":      fmt.Sprintf,\n\t\t},\n\t\tAutoPars: map[string]string{\n\t\t\t`*script.RunTime`: `rt`,\n\t\t},\n\t\tWriteFuncs: map[string]struct{}{\"CallContract\": {}}}\n}\n\n// ExecContract runs the name contract where txs contains the list of parameters and\n// params are the values of parameters\nfunc ExecContract(rt *RunTime, name, txs string, params ...any) (any, error) {\n\tcontract, ok := rt.vm.Objects[name]\n\tif !ok {\n\t\tlog.WithFields(log.Fields{\"contract_name\": name, \"type\": consts.ContractError}).Error(\"unknown contract\")\n\t\treturn nil, fmt.Errorf(eUnknownContract, name)\n\t}\n\tlogger := log.WithFields(log.Fields{\"contract_name\": name, \"type\": consts.ContractError})\n\tcblock := contract.GetCodeBlock()\n\tparnames := make(map[string]bool)\n\tpars := strings.Split(txs, `,`)\n\tif len(pars) != len(params) {\n\t\tlogger.WithFields(log.Fields{\"contract_params_len\": len(pars), \"contract_params_len_needed\": len(params), \"type\": consts.ContractError}).Error(\"wrong contract parameters pars\")\n\t\treturn ``, errContractPars\n\t}\n\tfor _, ipar := range pars {\n\t\tparnames[ipar] = true\n\t}\n\tif _, ok := rt.extend[Extend_loop+name]; ok {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ContractError, \"contract_name\": name}).Error(\"there is loop in contract\")\n\t\treturn nil, fmt.Errorf(eContractLoop, name)\n\t}\n\trt.extend[Extend_loop+name] = true\n\tdefer delete(rt.extend, Extend_loop+name)\n\n\tprevExtend := make(map[string]any)\n\tfor key, item := range rt.extend {\n\t\tif isSysVar(key) {\n\t\t\tcontinue\n\t\t}\n\t\tprevExtend[key] = item\n\t\tdelete(rt.extend, key)\n\t}\n\n\tvar isSignature bool\n\tif cblock.GetContractInfo().Tx != nil {\n\t\tfor _, tx := range *cblock.GetContractInfo().Tx {\n\t\t\tif !parnames[tx.Name] {\n\t\t\t\tif !strings.Contains(tx.Tags, TagOptional) {\n\t\t\t\t\tlogger.WithFields(log.Fields{\"transaction_name\": tx.Name, \"type\": consts.ContractError}).Error(\"transaction not defined\")\n\t\t\t\t\treturn ``, fmt.Errorf(eUndefinedParam, tx.Name)\n\t\t\t\t}\n\t\t\t\trt.extend[tx.Name] = reflect.New(tx.Type).Elem().Interface()\n\t\t\t}\n\t\t\tif tx.Name == `Signature` {\n\t\t\t\tisSignature = true\n\t\t\t}\n\t\t}\n\t}\n\tfor i, ipar := range pars {\n\t\trt.extend[ipar] = params[i]\n\t}\n\tprevthis := rt.extend[Extend_this_contract]\n\t_, nameContract := converter.ParseName(name)\n\trt.extend[Extend_this_contract] = nameContract\n\n\tprevparent := rt.extend[Extend_parent]\n\tparent := ``\n\tfor i := len(rt.blocks) - 1; i >= 0; i-- {\n\t\tif rt.blocks[i].Block.Type == ObjectType_Func && rt.blocks[i].Block.Parent != nil &&\n\t\t\trt.blocks[i].Block.Parent.Type == ObjectType_Contract {\n\t\t\tparent = rt.blocks[i].Block.Parent.GetContractInfo().Name\n\t\t\tfid, fname := converter.ParseName(parent)\n\t\t\tcid, _ := converter.ParseName(name)\n\t\t\tif len(fname) > 0 {\n\t\t\t\tif fid == 0 {\n\t\t\t\t\tparent = `@` + fname\n\t\t\t\t} else if fid == cid {\n\t\t\t\t\tparent = fname\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif err := rt.SubCost(CostContract); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar (\n\t\tstack Stacker\n\t\terr   error\n\t)\n\tif stack, ok = rt.extend[Extend_sc].(Stacker); ok {\n\t\tif err := stack.AppendStack(name); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif rt.extend[Extend_sc] != nil && isSignature {\n\t\tobj := rt.vm.Objects[`check_signature`]\n\t\tfinfo := obj.GetExtFuncInfo()\n\t\tif err := finfo.Func.(func(map[string]any, string) error)(rt.extend, name); err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"error\": err, \"func_name\": finfo.Name, \"type\": consts.ContractError}).Error(\"executing extended function\")\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfor _, method := range []string{`conditions`, `action`} {\n\t\tif block, ok := (*cblock).Objects[method]; ok && block.Type == ObjectType_Func {\n\t\t\trtemp := NewRunTime(rt.vm, rt.cost)\n\t\t\trt.extend[Extend_parent] = parent\n\t\t\t_, err = rtemp.Run(block.GetCodeBlock(), nil, rt.extend)\n\t\t\trt.cost = rtemp.cost\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"error\": err, \"method_name\": method, \"type\": consts.ContractError}).Error(\"executing contract method\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tif stack != nil {\n\t\tstack.PopStack(name)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trt.extend[Extend_parent] = prevparent\n\trt.extend[Extend_this_contract] = prevthis\n\tresult := rt.extend[Extend_result]\n\tfor key := range rt.extend {\n\t\tif isSysVar(key) {\n\t\t\tcontinue\n\t\t}\n\t\tdelete(rt.extend, key)\n\t}\n\n\tfor key, item := range prevExtend {\n\t\trt.extend[key] = item\n\t}\n\treturn result, nil\n}\n\n// ExContract executes the name contract in the state with specified parameters\nfunc ExContract(rt *RunTime, state uint32, name string, params *types.Map) (any, error) {\n\tname = StateName(state, name)\n\tcontract, ok := rt.vm.Objects[name]\n\tif !ok {\n\t\tlog.WithFields(log.Fields{\"contract_name\": name, \"type\": consts.ContractError}).Error(\"unknown contract\")\n\t\treturn nil, fmt.Errorf(eUnknownContract, name)\n\t}\n\tif params == nil {\n\t\tparams = types.NewMap()\n\t}\n\tlogger := log.WithFields(log.Fields{\"contract_name\": name, \"type\": consts.ContractError})\n\tnames := make([]string, 0)\n\tvals := make([]any, 0)\n\tcblock := contract.GetCodeBlock()\n\tif cblock.GetContractInfo().Tx != nil {\n\t\tfor _, tx := range *cblock.GetContractInfo().Tx {\n\t\t\tval, ok := params.Get(tx.Name)\n\t\t\tif !ok {\n\t\t\t\tif !strings.Contains(tx.Tags, TagOptional) {\n\t\t\t\t\tlogger.WithFields(log.Fields{\"transaction_name\": tx.Name, \"type\": consts.ContractError}).Error(\"transaction not defined\")\n\t\t\t\t\treturn nil, fmt.Errorf(eUndefinedParam, tx.Name)\n\t\t\t\t}\n\t\t\t\tval = reflect.New(tx.Type).Elem().Interface()\n\t\t\t}\n\t\t\tnames = append(names, tx.Name)\n\t\t\tvals = append(vals, val)\n\t\t}\n\t}\n\tif len(vals) == 0 {\n\t\tvals = append(vals, ``)\n\t}\n\treturn ExecContract(rt, name, strings.Join(names, `,`), vals...)\n}\n\n// GetSettings returns the value of the parameter\nfunc GetSettings(rt *RunTime, cntname, name string) (any, error) {\n\tcontract, found := rt.vm.Objects[cntname]\n\tif !found || contract.GetCodeBlock() == nil {\n\t\tlog.WithFields(log.Fields{\"contract_name\": cntname, \"type\": consts.ContractError}).Error(\"unknown contract\")\n\t\treturn nil, fmt.Errorf(\"unknown contract %s\", cntname)\n\t}\n\tcblock := contract.GetCodeBlock()\n\tinfo := cblock.GetContractInfo()\n\tif info != nil {\n\t\tif val, ok := info.Settings[name]; ok {\n\t\t\treturn val, nil\n\t\t}\n\t}\n\treturn ``, nil\n}\n\nfunc MemoryUsage(rt *RunTime) int64 {\n\treturn rt.mem\n}\n"
  },
  {
    "path": "packages/script/handle.go",
    "content": "package script\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype compileFunc func(*CodeBlocks, stateTypes, *Lexeme) error\n\nconst (\n\t// This is a list of identifiers for functions that will generate a bytecode for the corresponding cases.\n\t// Indexes of handle functions funcHandles = compileFunc[]\n\tcfNothing = iota\n\tcfError\n\tcfNameBlock\n\tcfFResult\n\tcfReturn\n\tcfIf\n\tcfElse\n\tcfFParam\n\tcfFType\n\tcfFTail\n\tcfFNameParam\n\tcfAssignVar\n\tcfAssign\n\tcfTX\n\tcfSettings\n\tcfConstName\n\tcfConstValue\n\tcfField\n\tcfFieldType\n\tcfFieldTag\n\tcfFields\n\tcfFieldComma\n\tcfFieldLine\n\tcfWhile\n\tcfContinue\n\tcfBreak\n\tcfCmdError\n\n\t//\tcfEval\n)\n\n// VarRegexp letter { letter | unicode_digit }\nvar VarRegexp = `^[a-zA-Z][a-zA-Z0-9_]*$`\n\nvar (\n\t// The array of functions corresponding to the constants cf...\n\tfuncHandles = map[int]compileFunc{\n\t\tcfNothing:    nil,\n\t\tcfError:      fError,\n\t\tcfNameBlock:  fNameBlock,\n\t\tcfFResult:    fFuncResult,\n\t\tcfReturn:     fReturn,\n\t\tcfIf:         fIf,\n\t\tcfElse:       fElse,\n\t\tcfFParam:     fFparam,\n\t\tcfFType:      fFtype,\n\t\tcfFTail:      fFtail,\n\t\tcfFNameParam: fFNameParam,\n\t\tcfAssignVar:  fAssignVar,\n\t\tcfAssign:     fAssign,\n\t\tcfTX:         fTx,\n\t\tcfSettings:   fSettings,\n\t\tcfConstName:  fConstName,\n\t\tcfConstValue: fConstValue,\n\t\tcfField:      fField,\n\t\tcfFieldType:  fFieldType,\n\t\tcfFieldTag:   fFieldTag,\n\t\tcfFields:     fFields,\n\t\tcfFieldComma: fFieldComma,\n\t\tcfFieldLine:  fFieldLine,\n\t\tcfWhile:      fWhile,\n\t\tcfContinue:   fContinue,\n\t\tcfBreak:      fBreak,\n\t\tcfCmdError:   fCmdError,\n\t}\n)\n\nfunc fError(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\terrors := []string{`no error`,\n\t\t`unknown command`,          // errUnknownCmd\n\t\t`must be the name`,         // errMustName\n\t\t`must be '{'`,              // errMustLCurly\n\t\t`must be '}'`,              // errMustRCurly\n\t\t`wrong parameters`,         // errParams\n\t\t`wrong variables`,          // errVars\n\t\t`must be type`,             // errVarType\n\t\t`must be '='`,              // errAssign\n\t\t`must be number or string`, // errStrNum\n\t}\n\tlogger := lexeme.GetLogger()\n\tif lexeme.Type == lexNewLine {\n\t\tlogger.WithFields(log.Fields{\"error\": errors[state], \"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"unexpected new line\")\n\t\treturn fmt.Errorf(`%s (unexpected new line) [Ln:%d]`, errors[state], lexeme.Line-1)\n\t}\n\tlogger.WithFields(log.Fields{\"error\": errors[state], \"lex_value\": lexeme.Value, \"type\": consts.ParseError}).Error(\"parsing error\")\n\treturn fmt.Errorf(`%s %x %v [Ln:%d Col:%d]`, errors[state], lexeme.Type, lexeme.Value, lexeme.Line, lexeme.Column)\n}\n\nfunc fNameBlock(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tvar itype ObjectType\n\tprev := (*buf)[len(*buf)-2]\n\tfblock := buf.peek()\n\tname := lexeme.Value.(string)\n\tswitch state {\n\tcase stateBlock:\n\t\titype = ObjectType_Contract\n\t\tname = StateName((*buf)[0].Owner.StateID, name)\n\t\tfblock.Info = &ContractInfo{ID: uint32(len(prev.Children) - 1), Name: name,\n\t\t\tOwner: (*buf)[0].Owner}\n\tdefault:\n\t\titype = ObjectType_Func\n\t\tfblock.Info = &FuncInfo{Name: name}\n\t}\n\tfblock.Type = itype\n\tif _, ok := prev.Objects[name]; ok {\n\t\tlexeme.GetLogger().WithFields(log.Fields{\"type\": consts.ParseError, \"contract\": prev.GetContractInfo().Name, \"lex_value\": name}).Errorf(\"%s redeclared in this contract\", itype)\n\t\treturn fmt.Errorf(\"%s '%s' redeclared in this contract '%s'\", itype, name, prev.GetContractInfo().Name)\n\t}\n\tprev.Objects[name] = &ObjInfo{Type: itype, Value: fblock}\n\treturn nil\n}\n\nfunc fFuncResult(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tfblock := buf.peek().GetFuncInfo()\n\t(*fblock).Results = append((*fblock).Results, lexeme.Value.(reflect.Type))\n\treturn nil\n}\n\nfunc fReturn(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.peek().Code.push(newByteCode(cmdReturn, lexeme.Line, 0))\n\treturn nil\n}\n\nfunc fCmdError(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.peek().Code.push(newByteCode(cmdError, lexeme.Line, lexeme.Value))\n\treturn nil\n}\n\nfunc fFparam(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tblock := buf.peek()\n\tif block.Type == ObjectType_Func && (state == stateFParam || state == stateFParamTYPE) {\n\t\tfblock := block.GetFuncInfo()\n\t\tif fblock.Names == nil {\n\t\t\tfblock.Params = append(fblock.Params, reflect.TypeOf(nil))\n\t\t} else {\n\t\t\tfor key := range *fblock.Names {\n\t\t\t\tif key[0] == '_' {\n\t\t\t\t\tname := key[1:]\n\t\t\t\t\tparams := append((*fblock.Names)[name].Params, reflect.TypeOf(nil))\n\t\t\t\t\toffset := append((*fblock.Names)[name].Offset, len(block.Vars))\n\t\t\t\t\t(*fblock.Names)[name] = FuncName{Params: params, Offset: offset}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif block.Objects == nil {\n\t\tblock.Objects = make(map[string]*ObjInfo)\n\t}\n\tif !regexp.MustCompile(VarRegexp).MatchString(lexeme.Value.(string)) {\n\t\tvar val = lexeme.Value.(string)\n\t\tif len(val) > 20 {\n\t\t\tval = val[:20] + \"...\"\n\t\t}\n\t\treturn fmt.Errorf(\"identifier expected, got '%s'\", val)\n\t}\n\tif _, ok := block.Objects[lexeme.Value.(string)]; ok {\n\t\tif state == stateFParamTYPE {\n\t\t\treturn fmt.Errorf(\"duplicate argument '%s'\", lexeme.Value.(string))\n\t\t} else if state == stateVarType {\n\t\t\treturn fmt.Errorf(\"'%s' redeclared in this code block\", lexeme.Value.(string))\n\t\t}\n\t}\n\tblock.Objects[lexeme.Value.(string)] = &ObjInfo{Type: ObjectType_Var, Value: &ObjInfo_Variable{Name: lexeme.Value.(string), Index: len(block.Vars)}}\n\tblock.Vars = append(block.Vars, reflect.TypeOf(nil))\n\treturn nil\n}\n\nfunc fFtype(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tblock := buf.peek()\n\tif block.Type == ObjectType_Func && state == stateFParam {\n\t\tfblock := block.GetFuncInfo()\n\t\tif fblock.Names == nil {\n\t\t\tfor pkey, param := range fblock.Params {\n\t\t\t\tif param == reflect.TypeOf(nil) {\n\t\t\t\t\tfblock.Params[pkey] = lexeme.Value.(reflect.Type)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor key := range *fblock.Names {\n\t\t\t\tif key[0] == '_' {\n\t\t\t\t\tfor pkey, param := range (*fblock.Names)[key[1:]].Params {\n\t\t\t\t\t\tif param == reflect.TypeOf(nil) {\n\t\t\t\t\t\t\t(*fblock.Names)[key[1:]].Params[pkey] = lexeme.Value.(reflect.Type)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor vkey, ivar := range block.Vars {\n\t\tif ivar == reflect.TypeOf(nil) {\n\t\t\tblock.Vars[vkey] = lexeme.Value.(reflect.Type)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fFtail(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tvar used bool\n\tblock := buf.peek()\n\n\tfblock := block.GetFuncInfo()\n\tif fblock.Names == nil {\n\t\tfor pkey, param := range fblock.Params {\n\t\t\tif param == reflect.TypeOf(nil) {\n\t\t\t\tif used {\n\t\t\t\t\treturn fmt.Errorf(`... parameter must be one`)\n\t\t\t\t}\n\t\t\t\tfblock.Params[pkey] = reflect.TypeOf([]any{})\n\t\t\t\tused = true\n\t\t\t}\n\t\t}\n\t\tblock.GetFuncInfo().Variadic = true\n\t} else {\n\t\tfor key := range *fblock.Names {\n\t\t\tif key[0] == '_' {\n\t\t\t\tname := key[1:]\n\t\t\t\tfor pkey, param := range (*fblock.Names)[name].Params {\n\t\t\t\t\tif param == reflect.TypeOf(nil) {\n\t\t\t\t\t\tif used {\n\t\t\t\t\t\t\treturn fmt.Errorf(`... parameter must be one`)\n\t\t\t\t\t\t}\n\t\t\t\t\t\t(*fblock.Names)[name].Params[pkey] = reflect.TypeOf([]any{})\n\t\t\t\t\t\tused = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toffset := append((*fblock.Names)[name].Offset, len(block.Vars))\n\t\t\t\t(*fblock.Names)[name] = FuncName{Params: (*fblock.Names)[name].Params,\n\t\t\t\t\tOffset: offset, Variadic: true}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tfor vkey, ivar := range block.Vars {\n\t\tif ivar == reflect.TypeOf(nil) {\n\t\t\tblock.Vars[vkey] = reflect.TypeOf([]any{})\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fFNameParam(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tblock := buf.peek()\n\n\tfblock := block.GetFuncInfo()\n\tif fblock.Names == nil {\n\t\tnames := make(map[string]FuncName)\n\t\tfblock.Names = &names\n\t}\n\tfor key := range *fblock.Names {\n\t\tif key[0] == '_' {\n\t\t\tdelete(*fblock.Names, key)\n\t\t}\n\t}\n\t(*fblock.Names)[`_`+lexeme.Value.(string)] = FuncName{}\n\treturn nil\n}\n\nfunc fIf(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.get(len(*buf) - 2).Code.push(newByteCode(cmdIf, lexeme.Line, buf.peek()))\n\treturn nil\n}\n\nfunc fWhile(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.get(len(*buf) - 2).Code.push(newByteCode(cmdWhile, lexeme.Line, buf.peek()))\n\tbuf.get(len(*buf) - 2).Code.push(newByteCode(cmdContinue, lexeme.Line, 0))\n\treturn nil\n}\n\nfunc fContinue(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.peek().Code.push(newByteCode(cmdContinue, lexeme.Line, 0))\n\treturn nil\n}\n\nfunc fBreak(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.peek().Code.push(newByteCode(cmdBreak, lexeme.Line, 0))\n\treturn nil\n}\n\nfunc fAssignVar(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tblock := buf.peek()\n\tvar (\n\t\tprev []*VarInfo\n\t\tivar VarInfo\n\t)\n\tif lexeme.Type == lexExtend {\n\t\tif isSysVar(lexeme.Value.(string)) {\n\t\t\tlexeme.GetLogger().WithFields(log.Fields{\"type\": consts.ParseError, \"lex_value\": lexeme.Value}).Error(\"modifying system variable\")\n\t\t\treturn fmt.Errorf(eSysVar, lexeme.Value.(string))\n\t\t}\n\t\tivar = VarInfo{Obj: &ObjInfo{Type: ObjectType_ExtVar, Value: &ObjInfo_ExtendVariable{Name: lexeme.Value.(string)}}, Owner: nil}\n\t} else {\n\t\tobjInfo, tobj := findVar(lexeme.Value.(string), buf)\n\t\tif objInfo == nil || objInfo.Type != ObjectType_Var {\n\t\t\tlexeme.GetLogger().WithFields(log.Fields{\"type\": consts.ParseError, \"lex_value\": lexeme.Value}).Error(\"unknown variable\")\n\t\t\treturn fmt.Errorf(`unknown variable '%s'`, lexeme.Value.(string))\n\t\t}\n\t\tivar = VarInfo{Obj: objInfo, Owner: tobj}\n\t}\n\tif len(block.Code) > 0 {\n\t\tif block.Code[len(block.Code)-1].Cmd == cmdAssignVar {\n\t\t\tprev = block.Code[len(block.Code)-1].Value.([]*VarInfo)\n\t\t}\n\t}\n\tprev = append(prev, &ivar)\n\tif len(prev) == 1 {\n\t\tblock.Code.push(newByteCode(cmdAssignVar, lexeme.Line, prev))\n\t} else {\n\t\tblock.Code[len(block.Code)-1] = newByteCode(cmdAssignVar, lexeme.Line, prev)\n\t}\n\treturn nil\n}\n\nfunc fAssign(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tbuf.peek().Code.push(newByteCode(cmdAssign, lexeme.Line, 0))\n\treturn nil\n}\n\nfunc fTx(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tcontract := buf.peek()\n\tlogger := lexeme.GetLogger()\n\tif contract.Type != ObjectType_Contract {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ParseError, \"contract_type\": contract.Type, \"lex_value\": lexeme.Value}).Error(\"data can only be in contract\")\n\t\treturn fmt.Errorf(`data can only be in contract`)\n\t}\n\t(*contract).GetContractInfo().Tx = new([]*FieldInfo)\n\treturn nil\n}\n\nfunc fSettings(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tcontract := buf.peek()\n\tif contract.Type != ObjectType_Contract {\n\t\tlogger := lexeme.GetLogger()\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ParseError, \"contract_type\": contract.Type, \"lex_value\": lexeme.Value}).Error(\"data can only be in contract\")\n\t\treturn fmt.Errorf(`settings can only be in contract`)\n\t}\n\t(*contract).GetContractInfo().Settings = make(map[string]any)\n\treturn nil\n}\n\nfunc fConstName(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tsets := buf.peek().GetContractInfo().Settings\n\tsets[lexeme.Value.(string)] = nil\n\treturn nil\n}\n\nfunc fConstValue(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tsets := buf.peek().GetContractInfo().Settings\n\tfor key, val := range sets {\n\t\tif val == nil {\n\t\t\tsets[key] = lexeme.Value\n\t\t\tbreak\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fField(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tinfo := buf.peek().GetContractInfo()\n\ttx := info.Tx\n\tif len(*tx) > 0 && (*tx)[len(*tx)-1].Type == reflect.TypeOf(nil) &&\n\t\t(*tx)[len(*tx)-1].Tags != `_` {\n\t\treturn fmt.Errorf(eDataType, lexeme.Line, lexeme.Column)\n\t}\n\n\tif !regexp.MustCompile(VarRegexp).MatchString(lexeme.Value.(string)) {\n\t\tvar val = lexeme.Value.(string)\n\t\tif len(val) > 20 {\n\t\t\tval = val[:20] + \"...\"\n\t\t}\n\t\treturn fmt.Errorf(\"identifier expected, got '%s'\", val)\n\t}\n\n\tif isSysVar(lexeme.Value.(string)) {\n\t\tlexeme.GetLogger().WithFields(log.Fields{\"type\": consts.ParseError, \"contract\": info.Name, \"lex_value\": lexeme.Value.(string)}).Error(\"param variable in the data section of the contract collides with the 'builtin' variable\")\n\t\treturn fmt.Errorf(eDataParamVarCollides, lexeme.Value.(string), info.Name)\n\t}\n\t*tx = append(*tx, &FieldInfo{Name: lexeme.Value.(string), Type: reflect.TypeOf(nil)})\n\treturn nil\n}\n\nfunc fFields(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\ttx := buf.peek().GetContractInfo().Tx\n\tif len(*tx) > 0 && (*tx)[len(*tx)-1].Type == nil {\n\t\treturn fmt.Errorf(eDataType, lexeme.Line, lexeme.Column)\n\t}\n\treturn nil\n}\n\nfunc fFieldComma(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\ttx := buf.peek().GetContractInfo().Tx\n\tif len(*tx) == 0 || (*tx)[len(*tx)-1].Type != nil {\n\t\treturn fmt.Errorf(eDataName, lexeme.Line, lexeme.Column)\n\t}\n\t(*tx)[len(*tx)-1].Tags = `_`\n\treturn nil\n}\n\nfunc fFieldLine(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\ttx := buf.peek().GetContractInfo().Tx\n\tif len(*tx) > 0 && (*tx)[len(*tx)-1].Type == nil {\n\t\treturn fmt.Errorf(eDataType, lexeme.Line, lexeme.Column)\n\t}\n\tfor i, field := range *tx {\n\t\tif field.Tags == `_` {\n\t\t\t(*tx)[i].Tags = ``\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fFieldType(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\ttx := buf.peek().GetContractInfo().Tx\n\tif len(*tx) == 0 || (*tx)[len(*tx)-1].Type != nil {\n\t\treturn fmt.Errorf(eDataName, lexeme.Line, lexeme.Column)\n\t}\n\tfor i, field := range *tx {\n\t\tif field.Type == reflect.TypeOf(nil) {\n\t\t\t(*tx)[i].Type = lexeme.Value.(reflect.Type)\n\t\t\t(*tx)[i].Original = lexeme.Ext\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc fFieldTag(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\ttx := buf.peek().GetContractInfo().Tx\n\tif len(*tx) == 0 || (*tx)[len(*tx)-1].Type == nil || len((*tx)[len(*tx)-1].Tags) != 0 {\n\t\treturn fmt.Errorf(eDataTag, lexeme.Line, lexeme.Column)\n\t}\n\tfor i := len(*tx) - 1; i >= 0; i-- {\n\t\tif i == len(*tx)-1 || (*tx)[i].Tags == `_` {\n\t\t\t(*tx)[i].Tags = lexeme.Value.(string)\n\t\t\tcontinue\n\t\t}\n\t\tbreak\n\t}\n\treturn nil\n}\n\nfunc fElse(buf *CodeBlocks, state stateTypes, lexeme *Lexeme) error {\n\tif buf.get(len(*buf)-2).Code.peek().Cmd != cmdIf {\n\t\treturn fmt.Errorf(`there is not if before %v [Ln:%d Col:%d]`, lexeme.Type, lexeme.Line, lexeme.Column)\n\t}\n\tbuf.get(len(*buf) - 2).Code.push(newByteCode(cmdElse, lexeme.Line, buf.peek()))\n\treturn nil\n}\n"
  },
  {
    "path": "packages/script/lex.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// The lexical analysis of the incoming program is implemented in this file. It is the first phase of compilation\n// where the incoming text is divided into a sequence of lexemes.\n\nconst (\n\t// Here are all the created lexemes\n\tlexUnknown = iota\n\tlexSys     // a system lexeme is different bracket, =, comma and so on.\n\tlexOper    // Operator is +, -, *, /\n\tlexNumber  // Number\n\tlexIdent   // Identifier\n\tlexNewLine // Line translation\n\tlexString  // String\n\tlexComment // Comment\n\tlexKeyword // Key word\n\tlexType    // Name of the type\n\tlexExtend  // Referring to an external variable or function - $myname\n\n\tlexError = 0xff\n\t// flags of lexical states\n\tlexfNext = 1\n\tlexfPush = 2\n\tlexfPop  = 4\n\tlexfSkip = 8\n\n\t// Constants for system lexemes\n\tisLPar   = 0x2801 // (\n\tisRPar   = 0x2901 // )\n\tisComma  = 0x2c01 // ,\n\tisDot    = 0x2e01 // .\n\tisColon  = 0x3a01 // :\n\tisEq     = 0x3d01 // =\n\tisLCurly = 0x7b01 // {\n\tisRCurly = 0x7d01 // }\n\tisLBrack = 0x5b01 // [\n\tisRBrack = 0x5d01 // ]\n\n\t// Constants for operations\n\tisNot      = 0x0021 // !\n\tisAsterisk = 0x002a // *\n\tisPlus     = 0x002b // +\n\tisMinus    = 0x002d // -\n\tisSign     = 0x012d // - unary\n\tisSolidus  = 0x002f // /\n\tisLess     = 0x003c // <\n\tisGreat    = 0x003e // >\n\tisNotEq    = 0x213d // !=\n\tisAnd      = 0x2626 // &&\n\tisLessEq   = 0x3c3d // <=\n\tisEqEq     = 0x3d3d // ==\n\tisGrEq     = 0x3e3d // >=\n\tisOr       = 0x7c7c // ||\n\n)\n\nconst (\n\t// The list of keyword identifiers\n\t// Constants for keywords\n\t//\tkeyUnknown = iota\n\tkeyContract = iota + 1\n\tkeyFunc\n\tkeyReturn\n\tkeyIf\n\tkeyElif\n\tkeyElse\n\tkeyWhile\n\tkeyTrue\n\tkeyFalse\n\tkeyVar\n\tkeyTX\n\tkeySettings\n\tkeyBreak\n\tkeyContinue\n\tkeyWarning\n\tkeyInfo\n\tkeyNil\n\tkeyAction\n\tkeyCond\n\tkeyTail\n\tkeyError\n)\n\nconst (\n\tmsgWarning = `warning`\n\tmsgError   = `error`\n\tmsgInfo    = `info`\n)\n\nconst (\n\tDtBool uint32 = iota + 1\n\tDtBytes\n\tDtInt\n\tDtAddress\n\tDtArray\n\tDtMap\n\tDtMoney\n\tDtFloat\n\tDtString\n\tDtFile\n)\n\ntype typeInfo struct {\n\tOriginal uint32\n\tType     reflect.Type\n}\n\nvar (\n\t// The list of keywords\n\tkeywords = map[string]uint32{\n\t\t`contract`:   keyContract,\n\t\t`func`:       keyFunc,\n\t\t`return`:     keyReturn,\n\t\t`if`:         keyIf,\n\t\t`elif`:       keyElif,\n\t\t`else`:       keyElse,\n\t\tmsgError:     keyError,\n\t\tmsgWarning:   keyWarning,\n\t\tmsgInfo:      keyInfo,\n\t\t`while`:      keyWhile,\n\t\t`data`:       keyTX,\n\t\t`settings`:   keySettings,\n\t\t`nil`:        keyNil,\n\t\t`action`:     keyAction,\n\t\t`conditions`: keyCond,\n\t\t`true`:       keyTrue,\n\t\t`false`:      keyFalse,\n\t\t`break`:      keyBreak,\n\t\t`continue`:   keyContinue,\n\t\t`var`:        keyVar,\n\t\t`...`:        keyTail}\n\n\t// list of available types\n\t// The list of types which save the corresponding 'reflect' type\n\ttypesMap = map[string]typeInfo{\n\t\t`bool`:    {Original: DtBool, Type: reflect.TypeOf(true)},\n\t\t`bytes`:   {Original: DtBytes, Type: reflect.TypeOf([]byte{})},\n\t\t`int`:     {Original: DtInt, Type: reflect.TypeOf(int64(0))},\n\t\t`address`: {Original: DtAddress, Type: reflect.TypeOf(int64(0))},\n\t\t`array`:   {Original: DtArray, Type: reflect.TypeOf([]any{})},\n\t\t`map`:     {Original: DtMap, Type: reflect.TypeOf(&types.Map{})},\n\t\t`money`:   {Original: DtMoney, Type: reflect.TypeOf(decimal.Zero)},\n\t\t`float`:   {Original: DtFloat, Type: reflect.TypeOf(0.0)},\n\t\t`string`:  {Original: DtString, Type: reflect.TypeOf(``)},\n\t\t`file`:    {Original: DtFile, Type: reflect.TypeOf(&types.Map{})},\n\t}\n)\n\nfunc GetFieldDefaultValue(fieldType uint32) any {\n\tswitch fieldType {\n\tcase DtBool:\n\t\treturn false\n\tcase DtFloat:\n\t\treturn float64(0)\n\tcase DtInt, DtAddress:\n\t\treturn int64(0)\n\tcase DtMoney:\n\t\treturn decimal.New(0, consts.MoneyDigits)\n\tcase DtString:\n\t\treturn \"\"\n\tcase DtBytes:\n\t\treturn []byte{}\n\tcase DtArray:\n\t\treturn []any{}\n\tcase DtMap:\n\t\treturn types.NewMap()\n\tcase DtFile:\n\t\treturn types.NewFile()\n\t}\n\treturn nil\n}\n\n// Lexeme contains information about language item\ntype Lexeme struct {\n\tType   uint32 // Type of the lexeme\n\tExt    uint32\n\tValue  any    // Value of lexeme\n\tLine   uint16 // Line of the lexeme\n\tColumn uint32 // Position inside the line\n}\n\nfunc NewLexeme(t uint32, ext uint32, value any, line uint16, column uint32) *Lexeme {\n\treturn &Lexeme{Type: t, Ext: ext, Value: value, Line: line, Column: column}\n}\n\n// GetLogger returns logger\nfunc (l *Lexeme) GetLogger() *log.Entry {\n\treturn log.WithFields(log.Fields{\"lex_type\": l.Type, \"lex_line\": l.Line, \"lex_column\": l.Column})\n}\n\ntype ifBuf struct {\n\tcount int\n\tpair  int\n\tstop  bool\n}\n\n// Lexemes is a slice of lexemes\ntype Lexemes []*Lexeme\n\n// The lexical analysis is based on the finite machine which is described in the file\n// tools/lextable/lextable.go. lextable.go generates a representation of a finite machine as an array\n// and records it in the file lex_table.go. In fact, the lexTable array is a set of states and\n// depending on the next sign, the machine goes into a new state.\n// lexParser parsers the input language source code\nfunc lexParser(input []rune) (Lexemes, error) {\n\tvar (\n\t\tcurState                                        uint8\n\t\tlength, line, off, offline, flags, start, lexID uint32\n\t)\n\n\tlexemes := make(Lexemes, 0, len(input)/4)\n\tirune := len(alphabet) - 1\n\n\t// This function according to the next symbol looks with help of lexTable what new state we will have,\n\t// whether we got the lexeme and what flags are displayed\n\ttodo := func(r rune) {\n\t\tvar letter uint8\n\t\tif r > 127 {\n\t\t\tletter = alphabet[irune]\n\t\t} else {\n\t\t\tletter = alphabet[r]\n\t\t}\n\t\tval := lexTable[curState][letter]\n\t\tcurState = uint8(val >> 16)\n\t\tlexID = (val >> 8) & 0xff\n\t\tflags = val & 0xff\n\t}\n\tlength = uint32(len(input)) + 1\n\tline = 1\n\tskip := false\n\tifbuf := make([]ifBuf, 0)\n\tfor off < length {\n\t\t// Here we go through the symbols one by one\n\t\tif off == length-1 {\n\t\t\ttodo(' ')\n\t\t} else {\n\t\t\ttodo(input[off])\n\t\t}\n\t\tif curState == lexError {\n\t\t\treturn nil, fmt.Errorf(`unknown lexeme '%s' [Ln:%d Col:%d]`,\n\t\t\t\tstring(input[off:off+1]), line, off-offline+1)\n\t\t}\n\t\tif (flags & lexfSkip) != 0 {\n\t\t\toff++\n\t\t\tskip = true\n\t\t\tcontinue\n\t\t}\n\t\t// If machine determined the completed lexeme, we record it in the list of lexemes.\n\t\tif lexID > 0 {\n\t\t\t// We do not start a stack for symbols but memorize the displacement when the parse of lexeme began.\n\t\t\t// To get a string of a lexeme we take a substring from the initial displacement to the current one.\n\t\t\t// We immediately write a string as values, a number or a binary representation of operations.\n\t\t\tvar ext uint32\n\t\t\tlexOff := off\n\t\t\tif (flags & lexfPop) != 0 {\n\t\t\t\tlexOff = start\n\t\t\t}\n\t\t\tright := off\n\t\t\tif (flags & lexfNext) != 0 {\n\t\t\t\tright++\n\t\t\t}\n\t\t\tif len(ifbuf) > 0 && ifbuf[len(ifbuf)-1].stop && lexID != lexNewLine {\n\t\t\t\tname := string(input[lexOff:right])\n\t\t\t\tif name != `else` && name != `elif` {\n\t\t\t\t\tfor i := 0; i < ifbuf[len(ifbuf)-1].count; i++ {\n\t\t\t\t\t\tlexemes = append(lexemes, NewLexeme(lexSys|(uint32('}')<<8), ext, uint32('}'), uint16(line), lexOff-offline+1))\n\t\t\t\t\t}\n\t\t\t\t\tifbuf = ifbuf[:len(ifbuf)-1]\n\t\t\t\t} else {\n\t\t\t\t\tifbuf[len(ifbuf)-1].stop = false\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar value any\n\t\t\tswitch lexID {\n\t\t\tcase lexNewLine:\n\t\t\t\tif input[lexOff] == rune(0x0a) {\n\t\t\t\t\tline++\n\t\t\t\t\toffline = off\n\t\t\t\t}\n\t\t\tcase lexSys:\n\t\t\t\tch := uint32(input[lexOff])\n\t\t\t\tlexID |= ch << 8\n\t\t\t\tvalue = ch\n\t\t\t\tif len(ifbuf) > 0 {\n\t\t\t\t\tif ch == '{' {\n\t\t\t\t\t\tifbuf[len(ifbuf)-1].pair++\n\t\t\t\t\t}\n\t\t\t\t\tif ch == '}' {\n\t\t\t\t\t\tifbuf[len(ifbuf)-1].pair--\n\t\t\t\t\t\tif ifbuf[len(ifbuf)-1].pair == 0 {\n\t\t\t\t\t\t\tifbuf[len(ifbuf)-1].stop = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase lexString, lexComment:\n\t\t\t\tval := string(input[lexOff+1 : right-1])\n\t\t\t\tif lexID == lexString && skip {\n\t\t\t\t\tskip = false\n\t\t\t\t\tval = strings.Replace(strings.Replace(val, `\\\"`, `\"`, -1), `\\t`, \"\\t\", -1)\n\t\t\t\t\tval = strings.Replace(strings.Replace(val, `\\r`, \"\\r\", -1), `\\n`, \"\\n\", -1)\n\t\t\t\t}\n\t\t\t\tvalue = val\n\t\t\t\tfor i, ch := range val {\n\t\t\t\t\tif ch == 0xa {\n\t\t\t\t\t\tline++\n\t\t\t\t\t\toffline = off + uint32(i) + 1\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase lexOper:\n\t\t\t\toper := []byte(string(input[lexOff:right]))\n\t\t\t\tvalue = binary.BigEndian.Uint32(append(make([]byte, 4-len(oper)), oper...))\n\t\t\tcase lexNumber:\n\t\t\t\tname := string(input[lexOff:right])\n\t\t\t\tif strings.ContainsAny(name, `.`) {\n\t\t\t\t\tif val, err := strconv.ParseFloat(name, 64); err == nil {\n\t\t\t\t\t\tvalue = val\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlog.WithFields(log.Fields{\"error\": err, \"value\": name, \"lex_line\": line, \"lex_col\": off - offline + 1, \"type\": consts.ConversionError}).Error(\"converting lex number to float\")\n\t\t\t\t\t\treturn nil, fmt.Errorf(`%v %s [Ln:%d Col:%d]`, err, name, line, off-offline+1)\n\t\t\t\t\t}\n\t\t\t\t} else if val, err := strconv.ParseInt(name, 10, 64); err == nil {\n\t\t\t\t\tvalue = val\n\t\t\t\t} else {\n\t\t\t\t\tlog.WithFields(log.Fields{\"error\": err, \"value\": name, \"lex_line\": line, \"lex_col\": off - offline + 1, \"type\": consts.ConversionError}).Error(\"converting lex number to int\")\n\t\t\t\t\treturn nil, fmt.Errorf(`%v %s [Ln:%d Col:%d]`, err, name, line, off-offline+1)\n\t\t\t\t}\n\t\t\tcase lexIdent:\n\t\t\t\tname := string(input[lexOff:right])\n\t\t\t\tif name[0] == '$' {\n\t\t\t\t\tlexID = lexExtend\n\t\t\t\t\tvalue = name[1:]\n\t\t\t\t} else if keyID, ok := keywords[name]; ok {\n\t\t\t\t\tswitch keyID {\n\t\t\t\t\tcase keyIf:\n\t\t\t\t\t\tifbuf = append(ifbuf, ifBuf{})\n\t\t\t\t\t\tlexID = lexKeyword | (keyID << 8)\n\t\t\t\t\t\tvalue = keyID\n\t\t\t\t\tcase keyElif:\n\t\t\t\t\t\tif len(ifbuf) > 0 {\n\t\t\t\t\t\t\tlexemes = append(lexemes,\n\t\t\t\t\t\t\t\tNewLexeme(lexKeyword|(keyElse<<8), ext, uint32(keyElse), uint16(line), lexOff-offline+1),\n\t\t\t\t\t\t\t\tNewLexeme(lexSys|('{'<<8), ext, uint32('{'), uint16(line), lexOff-offline+1))\n\t\t\t\t\t\t\tlexID = lexKeyword | (keyIf << 8)\n\t\t\t\t\t\t\tvalue = uint32(keyIf)\n\t\t\t\t\t\t\tifbuf[len(ifbuf)-1].count++\n\t\t\t\t\t\t}\n\t\t\t\t\tcase keyAction, keyCond:\n\t\t\t\t\t\tif len(lexemes) > 0 {\n\t\t\t\t\t\t\tlexf := *lexemes[len(lexemes)-1]\n\t\t\t\t\t\t\tif lexf.Type&0xff != lexKeyword || lexf.Value.(uint32) != keyFunc {\n\t\t\t\t\t\t\t\tlexemes = append(lexemes, NewLexeme(lexKeyword|(keyFunc<<8), ext, uint32(keyFunc), uint16(line), lexOff-offline+1))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvalue = name\n\t\t\t\t\tcase keyTrue:\n\t\t\t\t\t\tlexID = lexNumber\n\t\t\t\t\t\tvalue = true\n\t\t\t\t\tcase keyFalse:\n\t\t\t\t\t\tlexID = lexNumber\n\t\t\t\t\t\tvalue = false\n\t\t\t\t\tcase keyNil:\n\t\t\t\t\t\tlexID = lexNumber\n\t\t\t\t\t\tvalue = nil\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tlexID = lexKeyword | (keyID << 8)\n\t\t\t\t\t\tvalue = keyID\n\t\t\t\t\t}\n\t\t\t\t} else if tInfo, ok := typesMap[name]; ok {\n\t\t\t\t\tlexID = lexType\n\t\t\t\t\tvalue = tInfo.Type\n\t\t\t\t\text = tInfo.Original\n\t\t\t\t} else {\n\t\t\t\t\tvalue = name\n\t\t\t\t}\n\t\t\t}\n\t\t\tif lexID != lexComment {\n\t\t\t\tlexemes = append(lexemes, NewLexeme(lexID, ext, value, uint16(line), lexOff-offline+1))\n\t\t\t}\n\t\t}\n\t\tif (flags & lexfPush) != 0 {\n\t\t\tstart = off\n\t\t}\n\t\tif (flags & lexfNext) != 0 {\n\t\t\toff++\n\t\t}\n\t}\n\treturn lexemes, nil\n}\n\nfunc OriginalToString(original uint32) string {\n\tfor key, v := range typesMap {\n\t\tif v.Original == original {\n\t\t\treturn key\n\t\t}\n\t}\n\treturn ``\n}\n"
  },
  {
    "path": "packages/script/lex_table.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\n// This file was generated with lextable.go\n\nvar (\n\talphabet = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t0, 0, 0, 0, 0, 0, 0, 2, 20, 4, 14, 22, 0, 12, 0, 6, 7, 21, 25, 16, 26, 15, 27, 29,\n\t\t30, 30, 30, 30, 30, 30, 30, 30, 30, 24, 5, 17, 19, 18, 0, 23, 31, 31, 31, 31, 31, 31, 31, 31,\n\t\t31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 8, 28, 9, 0, 32, 3,\n\t\t31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,\n\t\t31, 31, 10, 13, 11, 0, 0, 33,\n\t}\n\tlexTable = [][34]uint32{\n\t\t{0xff0000, 0x501, 0x1, 0xe0003, 0xf0003, 0x501, 0x101, 0x101, 0x101, 0x101, 0x101, 0x101, 0x50003, 0xc0003, 0x101, 0xb0003, 0x101, 0x80003, 0x80003, 0xd0003, 0x80003, 0x201, 0x90003, 0x90003, 0x101, 0x201, 0x201, 0x70003, 0xff0000, 0x30003, 0x30003, 0x60003, 0x60003, 0x60003},\n\t\t{0x10001, 0x0, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001, 0x10001},\n\t\t{0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0x405, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000},\n\t\t{0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x30001, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x30001, 0x30001, 0xff0000, 0xff0000, 0xff0000},\n\t\t{0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x100001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001},\n\t\t{0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0x205, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000},\n\t\t{0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x404, 0x60001, 0x60001, 0x60001, 0x60001, 0x60001},\n\t\t{0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x40001, 0x204, 0x204, 0x204, 0x204, 0x204, 0x10005, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204},\n\t\t{0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x205, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204, 0x204},\n\t\t{0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0x60001, 0x60001, 0x60001, 0x60001, 0x60001},\n\t\t{0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001},\n\t\t{0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x20001, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x30001, 0x30001, 0x104, 0x104, 0x104},\n\t\t{0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0x205, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000, 0xff0000},\n\t\t{0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x205, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104, 0x104},\n\t\t{0xe0001, 0xe0001, 0xe0001, 0x605, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001, 0xe0001},\n\t\t{0xf0001, 0xf0001, 0xf0001, 0xf0001, 0x605, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xa0008, 0xf0001, 0xf0001, 0xf0001, 0xf0001, 0xf0001},\n\t\t{0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x705, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001, 0x40001},\n\t}\n)\n"
  },
  {
    "path": "packages/script/lex_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\ntype TestLexeme struct {\n\tInput  string\n\tOutput string\n}\n\nfunc (lexemes Lexemes) String(source []rune) (ret string) {\n\tfor _, item := range lexemes {\n\t\t//\t\tslex := string(source[item.Offset:item.Right])\n\t\tif item.Type == 0 {\n\t\t\titem.Value = `error`\n\t\t}\n\t\tret += fmt.Sprintf(\"[%d %v]\", item.Type, item.Value)\n\t}\n\treturn\n}\n\nfunc TestLexParser(t *testing.T) {\n\ttest := []TestLexeme{\n\t\t{\" my.test tail...) func 1 ...\", \"[4 my][11777 46][4 test][4 tail][5128 20][10497 41][520 2][3 1][5128 20]\"},\n\t\t{\"`my string` \\\"another String\\\"\" + `\"test \\\"subtest\\\" test\"`, \"[6 my string][6 another String][6 test \\\"subtest\\\" test]\"},\n\t\t{\"contract my { func init {}}\", \"[264 1][4 my][31489 123][520 2][4 init][31489 123][32001 125][32001 125]\"},\n\t\t{`callfunc( 1, name + 10)`, `[4 callfunc][10241 40][3 1][11265 44][4 name][2 43][3 10][10497 41]`},\n\t\t{`(ab <= 24 )|| (12>67) && (56==78)`, `[10241 40][4 ab][2 15421][3 24][10497 41][2 31868][10241 40][3 12][2 62][3 67][10497 41][2 9766][10241 40][3 56][2 15677][3 78][10497 41]`},\n\t\t{`!ab < !b && 12>=56 && qwe!=asd`, `[2 33][4 ab][2 60][2 33][4 b][2 9766][3 12][2 15933][3 56][2 9766][4 qwe][2 8509][4 asd]`},\n\t\t{`ab || 12 && 56`, `[4 ab][2 31868][3 12][2 9766][3 56]`},\n\t\t{\"12 /*rue \\n weweswe*/ 42\", `[3 12][3 42]`},\n\t\t{`true | 42`, `unknown lexeme   [Ln:1 Col:7]`},\n\t\t{\"(\\r\\n)\\x03 -\", \"unknown lexeme \u0003 [Ln:2 Col:3]\"},\n\t\t{` +( - )\t/ + // edeld lklm  3edwd`, `[2 43][10241 40][2 45][10497 41][2 47][2 43]`},\n\t\t{`23+13424 * 1000.01 test`, `[3 23][2 43][3 13424][2 42][3 1000.01][4 test]`},\n\t\t{` 0785/67+iname*(56-31)`, `[3 785][2 47][3 67][2 43][4 iname][2 42][10241 40][3 56][2 45][3 31][10497 41]`},\n\t\t{`myvar_45 - a_qwe + t81you - 345rt`, `unknown lexeme r [Ln:1 Col:32]`},\n\t\t{`10 + #mytable[id = 234].name * 20`, `[3 10][2 43][8961 35][4 mytable][23297 91][4 id][15617 61][3 234][23809 93][11777 46][4 name][2 42][3 20]`},\n\t}\n\tfor _, item := range test {\n\t\tsource := []rune(item.Input)\n\t\tif out, err := lexParser(source); err != nil {\n\t\t\tif err.Error() != item.Output {\n\t\t\t\tfmt.Println(string(source))\n\t\t\t\tt.Error(`error of lexical parser ` + err.Error())\n\t\t\t}\n\t\t} else if out.String(source) != item.Output {\n\t\t\tt.Error(`error of lexical parser ` + item.Input)\n\t\t\tfmt.Println(out.String(source))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/script/lextable/lextable.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\n// The program creates packages/script/lex_table.go files.\n\n// Action is a map of actions\ntype Action map[string][]string\n\n// States is a map of states\ntype States map[string]Action\n\nconst (\n\t// AlphaSize is the length of alphabet\n\tAlphaSize = 34\n)\n\n/*\nHere we define the alphabet with which our language will work and describe the state machine that\npasses from one state to another depending on the next received character.\nThis program converts the list of states into a numeric array and saves it as packages/script/lex_table.go\n*/\nvar (\n\ttable  [][AlphaSize]uint32\n\tlexeme = map[string]uint32{\n\t\t``:        0,\n\t\t`sys`:     1,\n\t\t`oper`:    2,\n\t\t`number`:  3,\n\t\t`ident`:   4,\n\t\t`newline`: 5,\n\t\t`string`:  6,\n\t\t`comment`: 7,\n\t}\n\tflags = map[string]uint32{\n\t\t`next`: 1,\n\t\t`push`: 2,\n\t\t`pop`:  4,\n\t\t`skip`: 8,\n\t}\n\talphabet = []byte{\n\t\t0x01, //default\n\t\t0x0a, //newline\n\t\t' ',  //space\n\t\t'`',  //back quotes\n\t\t'\"',  //double quotes\n\t\t';',\n\t\t'(',\n\t\t')',\n\t\t'[',\n\t\t']',\n\t\t'{',\n\t\t'}',\n\t\t'&',\n\t\t'|',\n\t\t'#',\n\t\t'.',\n\t\t',',\n\t\t'<',\n\t\t'>',\n\t\t'=',\n\t\t'!',\n\t\t'*',\n\t\t'$',\n\t\t'@',\n\t\t':',\n\t\t'+',\n\t\t'-',\n\t\t'/',\n\t\t'\\\\',\n\t\t'0',\n\t\t'1',\n\t\t'a',\n\t\t'_',\n\t\t128,\n\t}\n\t/*\n\t\tIn states we have designated for\n\t\td - all characters that are not specified in the state\n\t\tn - 0x0a,\n\t\ts - space,\n\t\tq - back quotes `,\n\t\tQ - double quotes,\n\t\tr - characters >= 128,\n\t\ta - A-Z and a-z,\n\t\t1 - 1-9\n\t\tState names are used as keys, and possible character sets are listed in the value object\n\t\tand then for each such set there is a new state where the transition should be made, then the name of the token,\n\t\tif we need to return to the initial state and the service flags are the third parameter,\n\t\twhich indicate what to do with the current symbol.\n\t\tFor example, we have the state main and the incoming symbol /. push says to remember it in a separate stack and\n\t\tnext - go to the next character, while we change the state to solidus.\n\t\tTake the next character and look at the state of solidus\n\t\tIf we have / or * - then we go into the comment state, so they start with // or / *.\n\t\tAt the same time, you can see that for each comment, there are different subsequent states, since they end\n\t\tthey are different symbols. And if we have the next character not / and not *, then we are all that we have\n\t\twrite to the stack (/) as a token of type oper, clear the stack and return to the main state.\n\t*/\n\tstates = `{\n\t\"main\": {\n\t\t\t\"n;\": [\"main\", \"newline\", \"next\"],\n\t\t\t\"()#[],{}:\": [\"main\", \"sys\", \"next\"],\n\t\t\t\"s\": [\"main\", \"\", \"next\"],\n\t\t\t\"q\": [\"string\", \"\", \"push next\"],\n\t\t\t\"Q\": [\"dstring\", \"\", \"push next\"],\n\t\t\t\"&\": [\"and\", \"\", \"push next\"],\n\t\t\t\"|\": [\"or\", \"\", \"push next\"],\n\t\t\t\"=\": [\"eq\", \"\", \"push next\"],\n\t\t\t\"/\": [\"solidus\", \"\", \"push next\"],\n\t\t\t\"<>!\": [\"oneq\", \"\", \"push next\"],\n\t\t\t\"*+-\": [\"main\", \"oper\", \"next\"],\n\t\t\t\"01\": [\"number\", \"\", \"push next\"],\n\t\t\t\"a_r\": [\"ident\", \"\", \"push next\"],\n\t\t\t\"@$\": [\"mustident\", \"\", \"push next\"],\n\t\t\t\".\": [\"dot\", \"\", \"push next\"],\n\t\t\t\"d\": [\"error\", \"\", \"\"]\n\t\t},\n\t\"string\": {\n\t\t\t\"q\": [\"main\", \"string\", \"pop next\"],\n\t\t\t\"d\": [\"string\", \"\", \"next\"]\n\t\t},\n\t\"dstring\": {\n\t\t\t\"Q\": [\"main\", \"string\", \"pop next\"],\n\t\t\t\"\\\\\": [\"dslash\", \"\", \"skip\"],\t\t\t\n\t\t\t\"d\": [\"dstring\", \"\", \"next\"]\n\t\t},\n\t\"dslash\": {\n\t\t\"d\": [\"dstring\", \"\", \"next\"]\n\t},\t\t\n\t\"dot\": {\n\t\t\".\": [\"ddot\", \"\", \"next\"],\n\t\t\"01\": [\"number\", \"\", \"next\"],\n\t\t\"d\": [\"main\", \"sys\", \"pop\"]\n\t},\n\t\"ddot\": {\n\t\t\".\": [\"main\", \"ident\", \"pop next\"],\n\t\t\"d\": [\"error\", \"\", \"\"]\n\t},\n\t\"and\": {\n\t\t\t\"&\": [\"main\", \"oper\", \"pop next\"],\n\t\t\t\"d\": [\"error\", \"\", \"\"]\n\t\t},\n\t\"or\": {\n\t\t\t\"|\": [\"main\", \"oper\", \"pop next\"],\n\t\t\t\"d\": [\"error\", \"\", \"\"]\n\t\t},\n\t\"eq\": {\n\t\t\t\"=\": [\"main\", \"oper\", \"pop next\"],\n\t\t\t\"d\": [\"main\", \"sys\", \"pop\"]\n\t\t},\n\t\"solidus\": {\n\t\t\t\"/\": [\"comline\", \"\", \"pop next\"],\n\t\t\t\"*\": [\"comment\", \"\", \"next\"],\n\t\t\t\"d\": [\"main\", \"oper\", \"pop\"]\n\t\t},\n\t\"oneq\": {\n\t\t\t\"=\": [\"main\", \"oper\", \"pop next\"],\n\t\t\t\"d\": [\"main\", \"oper\", \"pop\"]\n\t\t},\n\t\"number\": {\n\t\t\t\"01.\": [\"number\", \"\", \"next\"],\n\t\t\t\"a_r\": [\"error\", \"\", \"\"],\n\t\t\t\"d\": [\"main\", \"number\", \"pop\"]\n\t\t},\n\t\"ident\": {\n\t\t\t\"01a_r\": [\"ident\", \"\", \"next\"],\n\t\t\t\"d\": [\"main\", \"ident\", \"pop\"]\n\t\t},\n\t\"mustident\": {\n\t\t\"01a_r\": [\"ident\", \"\", \"next\"],\n\t\t\"d\": [\"error\", \"\", \"\"]\n\t},\n\t\"comment\": {\n\t\t\t\"*\": [\"comstop\", \"\", \"next\"],\n\t\t\t\"d\": [\"comment\", \"\", \"next\"]\n\t\t},\n\t\"comstop\": {\n\t\t\t\"/\": [\"main\", \"comment\", \"pop next\"],\n\t\t\t\"d\": [\"comment\", \"\", \"next\"]\n\t\t},\n\t\"comline\": {\n\t\t\t\"n\": [\"main\", \"\", \"\"],\n\t\t\t\"d\": [\"comline\", \"\", \"next\"]\n\t\t}\n}`\n)\n\nfunc main() {\n\tvar alpha [129]byte\n\tfor ind, ch := range alphabet {\n\t\ti := byte(ind)\n\t\tswitch ch {\n\t\tcase ' ':\n\t\t\talpha[0x09] = i\n\t\t\talpha[0x0d] = i\n\t\t\talpha[' '] = i\n\t\tcase '1':\n\t\t\tfor k := '1'; k <= '9'; k++ {\n\t\t\t\talpha[k] = i\n\t\t\t}\n\t\tcase 'a':\n\t\t\tfor k := 'A'; k <= 'Z'; k++ {\n\t\t\t\talpha[k] = i\n\t\t\t}\n\t\t\tfor k := 'a'; k <= 'z'; k++ {\n\t\t\t\talpha[k] = i\n\t\t\t}\n\t\tcase 128:\n\t\t\talpha[128] = i\n\t\tdefault:\n\t\t\talpha[ch] = i\n\t\t}\n\t}\n\tout := `package script\n\t// This file was generated with lextable.go\n\t\nvar (\n\t\talphabet = []byte{`\n\tfor i, ch := range alpha {\n\t\tout += fmt.Sprintf(`%d,`, ch)\n\t\tif i > 0 && i%24 == 0 {\n\t\t\tout += \"\\r\\n\\t\\t\\t\"\n\t\t}\n\t}\n\tout += \"\\r\\n\\t\\t}\\r\\n\"\n\n\tvar (\n\t\tdata States\n\t)\n\tstate2int := map[string]uint{`main`: 0}\n\tif err := json.Unmarshal([]byte(states), &data); err != nil {\n\t\tfmt.Println(err)\n\t}\n\tfor key := range data {\n\t\tif key != `main` {\n\t\t\tstate2int[key] = uint(len(state2int))\n\t\t}\n\t}\n\ttable = make([][AlphaSize]uint32, len(state2int))\n\tfor key, istate := range data {\n\t\tcurstate := state2int[key]\n\t\tfor i := range table[curstate] {\n\t\t\ttable[curstate][i] = 0xFE0000\n\t\t}\n\t\tfmt.Println(state2int)\n\t\tfor skey, sval := range istate {\n\t\t\tvar val uint32\n\t\t\tif sval[0] == `error` {\n\t\t\t\tval = 0xff0000\n\t\t\t} else {\n\t\t\t\tval = uint32(state2int[sval[0]] << 16) // new state\n\t\t\t}\n\t\t\tval |= lexeme[sval[1]] << 8 // lexeme\n\t\t\tcmds := strings.Split(sval[2], ` `)\n\t\t\tvar flag uint32\n\t\t\tfor _, icmd := range cmds {\n\t\t\t\tflag |= flags[icmd]\n\t\t\t}\n\t\t\tval |= flag\n\t\t\tfor _, ch := range []byte(skey) {\n\t\t\t\tvar ind int\n\t\t\t\tswitch ch {\n\t\t\t\tcase 'd':\n\t\t\t\t\tind = 0\n\t\t\t\tcase 'n':\n\t\t\t\t\tind = 1\n\t\t\t\tcase 's':\n\t\t\t\t\tind = 2\n\t\t\t\tcase 'q':\n\t\t\t\t\tind = 3\n\t\t\t\tcase 'Q':\n\t\t\t\t\tind = 4\n\t\t\t\tcase 'r':\n\t\t\t\t\tind = AlphaSize - 1\n\t\t\t\tdefault:\n\t\t\t\t\tfor k, ach := range alphabet {\n\t\t\t\t\t\tif ach == ch {\n\t\t\t\t\t\t\tind = k\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttable[curstate][ind] = val\n\t\t\t\tif ind == 0 { // default value\n\t\t\t\t\tfor i := range table[curstate] {\n\t\t\t\t\t\tif table[curstate][i] == 0xFE0000 {\n\t\t\t\t\t\t\ttable[curstate][i] = val\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tout += \"\\t\\tlexTable = [][\" + fmt.Sprint(AlphaSize) + \"]uint32{\\r\\n\"\n\tfor _, line := range table {\n\t\tout += \"\\t\\t\\t{\"\n\t\tfor _, ival := range line {\n\t\t\tout += fmt.Sprintf(\" 0x%x,\", ival)\n\t\t}\n\t\tout += \"\\r\\n\\t\\t\\t},\\r\\n\"\n\t}\n\tout += \"\\t\\t\\t}\\r\\n)\\r\\n\"\n\terr := os.WriteFile(\"../lex_table.go\", []byte(out), 0644)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t}\n\n}\n"
  },
  {
    "path": "packages/script/runtime.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tstatusNormal = iota\n\tstatusReturn\n\tstatusContinue\n\tstatusBreak\n\n\t// Decimal is the constant string for decimal type\n\tDecimal = `decimal.Decimal`\n\t// Interface is the constant string for interface type\n\tInterface = `interface`\n\tFile      = `*types.Map`\n\n\tbrackets = `[]`\n\n\tmaxArrayIndex = 1000000\n\tmaxMapCount   = 100000\n\tmaxCallDepth  = 1000\n\tmemoryLimit   = 128 << 20 // 128 MB\n\tMaxErrLen     = 150\n)\n\nvar sysVars = map[string]struct{}{\n\tsysVars_block:               {},\n\tsysVars_block_key_id:        {},\n\tsysVars_block_time:          {},\n\tsysVars_data:                {},\n\tsysVars_ecosystem_id:        {},\n\tsysVars_key_id:              {},\n\tsysVars_account_id:          {},\n\tsysVars_node_position:       {},\n\tsysVars_parent:              {},\n\tsysVars_original_contract:   {},\n\tsysVars_sc:                  {},\n\tsysVars_contract:            {},\n\tsysVars_stack:               {},\n\tsysVars_this_contract:       {},\n\tsysVars_time:                {},\n\tsysVars_type:                {},\n\tsysVars_txcost:              {},\n\tsysVars_txhash:              {},\n\tsysVars_guest_key:           {},\n\tsysVars_guest_account:       {},\n\tsysVars_black_hole_key:      {},\n\tsysVars_black_hole_account:  {},\n\tsysVars_white_hole_key:      {},\n\tsysVars_white_hole_account:  {},\n\tsysVars_gen_block:           {},\n\tsysVars_time_limit:          {},\n\tsysVars_pre_block_data_hash: {},\n}\n\nvar (\n\tErrMemoryLimit = errors.New(\"Memory limit exceeded\")\n\t//ErrVMTimeLimit returns when the time limit exceeded\n\tErrVMTimeLimit = errors.New(`time limit exceeded`)\n)\n\n// VMError represents error of VM\ntype VMError struct {\n\tType  string `json:\"type\"`\n\tError string `json:\"error\"`\n}\n\ntype blockStack struct {\n\tBlock  *CodeBlock\n\tOffset int\n}\n\n// ErrInfo stores info about current contract or function\ntype ErrInfo struct {\n\tName string\n\tLine uint16\n}\n\n// RunTime is needed for the execution of the byte-code\ntype RunTime struct {\n\tstack     []any\n\tblocks    []*blockStack\n\tvars      []any\n\textend    map[string]any\n\tvm        *VM\n\tcost      int64 //cost remaining\n\terr       error\n\tunwrap    bool\n\ttimeLimit bool\n\tcallDepth uint16\n\tmem       int64\n\tmemVars   map[any]int64\n\terrInfo   ErrInfo\n}\n\n// NewRunTime creates a new RunTime for the virtual machine\nfunc NewRunTime(vm *VM, cost int64) *RunTime {\n\treturn &RunTime{\n\t\tstack:   make([]any, 0, 1024),\n\t\tvm:      vm,\n\t\tcost:    cost,\n\t\tmemVars: make(map[any]int64),\n\t}\n}\n\nfunc isSysVar(name string) bool {\n\tif _, ok := sysVars[name]; ok || strings.HasPrefix(name, Extend_loop) {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (rt *RunTime) callFunc(cmd uint16, obj *ObjInfo) (err error) {\n\tvar (\n\t\tcount, in int\n\t)\n\tif rt.callDepth >= maxCallDepth {\n\t\treturn fmt.Errorf(\"max call depth\")\n\t}\n\n\trt.callDepth++\n\tdefer func() {\n\t\trt.callDepth--\n\t}()\n\n\tsize := rt.len()\n\tin = obj.getInParams()\n\tif rt.unwrap && cmd == cmdCallVariadic && size > 1 &&\n\t\treflect.TypeOf(rt.stack[size-2]).String() == `[]interface {}` {\n\t\tcount = rt.getStack(size - 1).(int)\n\t\tarr := rt.getStack(size - 2).([]any)\n\t\trt.resetByIdx(size - 2)\n\t\tfor _, item := range arr {\n\t\t\trt.push(item)\n\t\t}\n\t\trt.push(count - 1 + len(arr))\n\t\tsize = rt.len()\n\t}\n\trt.unwrap = false\n\tif cmd == cmdCallVariadic {\n\t\tcount = rt.getStack(size - 1).(int)\n\t\tsize--\n\t} else {\n\t\tcount = in\n\t}\n\tif obj.Type == ObjectType_Func {\n\t\tvar imap map[string][]any\n\t\tfinfo := obj.GetCodeBlock().GetFuncInfo()\n\t\tif finfo.Names != nil {\n\t\t\tif rt.getStack(size-1) != nil {\n\t\t\t\timap = rt.getStack(size - 1).(map[string][]any)\n\t\t\t}\n\t\t\trt.resetByIdx(size - 1)\n\t\t\tsize = rt.len()\n\t\t}\n\t\tif cmd == cmdCallVariadic {\n\t\t\tparcount := count + 1 - in\n\t\t\tif parcount < 0 {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError}).Error(errWrongCountPars)\n\t\t\t\treturn errWrongCountPars\n\t\t\t}\n\t\t\tpars := make([]any, parcount)\n\t\t\tshift := size - parcount\n\t\t\tfor i := parcount; i > 0; i-- {\n\t\t\t\tpars[i-1] = rt.stack[size+i-parcount-1]\n\t\t\t}\n\t\t\trt.resetByIdx(shift)\n\t\t\trt.push(pars)\n\t\t}\n\t\tif rt.len() < len(finfo.Params) {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError}).Error(errWrongCountPars)\n\t\t\treturn errWrongCountPars\n\t\t}\n\t\tfor i, v := range finfo.Params {\n\t\t\tswitch v.Kind() {\n\t\t\tcase reflect.String, reflect.Int64:\n\t\t\t\toffset := rt.len() - in + i\n\t\t\t\tif v.Kind() == reflect.Int64 {\n\t\t\t\t\trv := reflect.ValueOf(rt.stack[offset])\n\t\t\t\t\tswitch rv.Kind() {\n\t\t\t\t\tcase reflect.Float64:\n\t\t\t\t\t\tval, _ := converter.ValueToInt(rt.stack[offset])\n\t\t\t\t\t\trt.stack[offset] = val\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif reflect.TypeOf(rt.stack[offset]) != v {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError}).Error(fmt.Sprintf(eTypeParam, i+1))\n\t\t\t\t\treturn fmt.Errorf(eTypeParam, i+1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif finfo.Names != nil {\n\t\t\trt.push(imap)\n\t\t}\n\t\t_, err = rt.RunCode(obj.GetCodeBlock())\n\t\treturn\n\t}\n\n\tvar (\n\t\tstack  Stacker\n\t\tok     bool\n\t\tresult []reflect.Value\n\t\tlimit  = 0\n\t\tfinfo  = obj.GetExtFuncInfo()\n\t\tfoo    = reflect.ValueOf(finfo.Func)\n\t\tpars   = make([]reflect.Value, in)\n\t)\n\tif stack, ok = rt.extend[Extend_sc].(Stacker); ok {\n\t\tif err := stack.AppendStack(finfo.Name); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\trt.extend[Extend_rt] = rt\n\tauto := 0\n\tfor k := 0; k < in; k++ {\n\t\tif len(finfo.Auto[k]) > 0 {\n\t\t\tauto++\n\t\t}\n\t}\n\tshift := size - count + auto\n\tif finfo.Variadic {\n\t\tshift = size - count\n\t\tcount += auto\n\t\tlimit = count - in + 1\n\t}\n\ti := count\n\tfor ; i > limit; i-- {\n\t\tif len(finfo.Auto[count-i]) > 0 {\n\t\t\tpars[count-i] = reflect.ValueOf(rt.extend[finfo.Auto[count-i]])\n\t\t\tauto--\n\t\t} else {\n\t\t\tpars[count-i] = reflect.ValueOf(rt.stack[size-i+auto])\n\t\t}\n\t\tif !pars[count-i].IsValid() {\n\t\t\tpars[count-i] = reflect.Zero(reflect.TypeOf(``))\n\t\t}\n\t}\n\tif i > 0 && size-i >= 0 {\n\t\tpars[in-1] = reflect.ValueOf(rt.stack[size-i : size])\n\t} else {\n\t\tif !pars[in-1].IsValid() {\n\t\t\tpars[in-1] = reflect.Zero(finfo.Params[in-1])\n\t\t}\n\t}\n\tif finfo.Name == `ExecContract` && (pars[2].Kind() != reflect.String || !pars[3].IsValid()) {\n\t\treturn fmt.Errorf(`unknown function %v`, pars[1])\n\t}\n\tif finfo.Variadic {\n\t\tresult = foo.CallSlice(pars)\n\t} else {\n\t\tresult = foo.Call(pars)\n\t}\n\tif shift < 0 {\n\t\tshift = 0\n\t}\n\trt.resetByIdx(shift)\n\tif stack != nil {\n\t\tstack.PopStack(finfo.Name)\n\t}\n\n\tfor i, ret := range result {\n\t\t// first return value of every extend function that makes queries to DB is cost\n\t\tif _, ok := rt.vm.FuncCallsDB[finfo.Name]; ok && i == 0 {\n\t\t\tif err = rt.SubCost(ret.Int()); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif finfo.Results[i].String() == `error` {\n\t\t\tif ret.Interface() != nil {\n\t\t\t\trt.errInfo = ErrInfo{Name: finfo.Name}\n\t\t\t\treturn ret.Interface().(error)\n\t\t\t}\n\t\t} else {\n\t\t\trt.push(ret.Interface())\n\t\t}\n\t}\n\treturn\n}\n\nfunc (rt *RunTime) extendFunc(name string) error {\n\tvar (\n\t\tok bool\n\t\tf  any\n\t)\n\tif f, ok = rt.extend[name]; !ok || reflect.ValueOf(f).Kind() != reflect.Func {\n\t\treturn fmt.Errorf(`unknown function %s`, name)\n\t}\n\tsize := rt.len()\n\tfoo := reflect.ValueOf(f)\n\n\tcount := foo.Type().NumIn()\n\tpars := make([]reflect.Value, count)\n\tfor i := count; i > 0; i-- {\n\t\tpars[count-i] = reflect.ValueOf(rt.stack[size-i])\n\t}\n\tresult := foo.Call(pars)\n\n\trt.resetByIdx(size - count)\n\tfor i, iret := range result {\n\t\tif foo.Type().Out(i).String() == `error` {\n\t\t\tif iret.Interface() != nil {\n\t\t\t\treturn iret.Interface().(error)\n\t\t\t}\n\t\t} else {\n\t\t\trt.push(iret.Interface())\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc calcMem(v any) (mem int64) {\n\trv := reflect.ValueOf(v)\n\n\tswitch rv.Kind() {\n\tcase reflect.Bool:\n\t\tmem = 1\n\tcase reflect.Int8, reflect.Uint8:\n\t\tmem = 1\n\tcase reflect.Int16, reflect.Uint16:\n\t\tmem = 2\n\tcase reflect.Int32, reflect.Uint32:\n\t\tmem = 4\n\tcase reflect.Int64, reflect.Uint64, reflect.Int, reflect.Uint:\n\t\tmem = 8\n\tcase reflect.Float32:\n\t\tmem = 4\n\tcase reflect.Float64:\n\t\tmem = 8\n\tcase reflect.String:\n\t\tmem += int64(rv.Len())\n\tcase reflect.Slice, reflect.Array:\n\t\tmem = 12\n\t\tfor i := 0; i < rv.Len(); i++ {\n\t\t\tmem += calcMem(rv.Index(i).Interface())\n\t\t}\n\tcase reflect.Map:\n\t\tmem = 4\n\t\tfor _, k := range rv.MapKeys() {\n\t\t\tmem += calcMem(k.Interface())\n\t\t\tmem += calcMem(rv.MapIndex(k).Interface())\n\t\t}\n\tdefault:\n\t\tmem = int64(unsafe.Sizeof(v))\n\t}\n\n\treturn\n}\n\nfunc (rt *RunTime) setExtendVar(k string, v any) {\n\trt.extend[k] = v\n\trt.recalcMemExtendVar(k)\n}\n\nfunc (rt *RunTime) recalcMemExtendVar(k string) {\n\tmem := calcMem(rt.extend[k])\n\trt.mem += mem - rt.memVars[k]\n\trt.memVars[k] = mem\n}\n\nfunc (rt *RunTime) addVar(v any) {\n\trt.vars = append(rt.vars, v)\n\tmem := calcMem(v)\n\trt.memVars[len(rt.vars)-1] = mem\n\trt.mem += mem\n}\n\nfunc (rt *RunTime) setVar(k int, v any) {\n\trt.vars[k] = v\n\trt.recalcMemVar(k)\n}\n\nfunc (rt *RunTime) recalcMemVar(k int) {\n\tmem := calcMem(rt.vars[k])\n\trt.mem += mem - rt.memVars[k]\n\trt.memVars[k] = mem\n}\n\nfunc valueToBool(v any) bool {\n\tswitch val := v.(type) {\n\tcase int:\n\t\tif val != 0 {\n\t\t\treturn true\n\t\t}\n\tcase int64:\n\t\tif val != 0 {\n\t\t\treturn true\n\t\t}\n\tcase float64:\n\t\tif val != 0.0 {\n\t\t\treturn true\n\t\t}\n\tcase bool:\n\t\treturn val\n\tcase string:\n\t\treturn len(val) > 0\n\tcase []uint8:\n\t\treturn len(val) > 0\n\tcase []any:\n\t\treturn val != nil && len(val) > 0\n\tcase map[string]any:\n\t\treturn val != nil && len(val) > 0\n\tcase map[string]string:\n\t\treturn val != nil && len(val) > 0\n\tcase *types.Map:\n\t\treturn val != nil && val.Size() > 0\n\tdefault:\n\t\tdec, _ := decimal.NewFromString(fmt.Sprintf(`%v`, val))\n\t\treturn dec.Cmp(decimal.Zero) != 0\n\t}\n\treturn false\n}\n\n// ValueToFloat converts interface (string, float64 or int64) to float64\nfunc ValueToFloat(v any) (ret float64) {\n\tvar err error\n\tswitch val := v.(type) {\n\tcase float64:\n\t\tret = val\n\tcase int64:\n\t\tret = float64(val)\n\tcase string:\n\t\tret, err = strconv.ParseFloat(val, 64)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err, \"value\": val}).Error(\"converting value from string to float\")\n\t\t}\n\tcase decimal.Decimal:\n\t\tret = val.InexactFloat64()\n\t}\n\treturn\n}\n\n// ValueToDecimal converts interface (string, float64, Decimal or int64) to Decimal\nfunc ValueToDecimal(v any) (ret decimal.Decimal, err error) {\n\tswitch val := v.(type) {\n\tcase float64:\n\t\tret = decimal.NewFromFloat(val).Floor()\n\tcase string:\n\t\tret, err = decimal.NewFromString(val)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err, \"value\": val}).Error(\"converting value from string to decimal\")\n\t\t} else {\n\t\t\tret = ret.Floor()\n\t\t}\n\tcase int64:\n\t\tret = decimal.New(val, 0)\n\tdefault:\n\t\tret = val.(decimal.Decimal)\n\t}\n\treturn\n}\n\n// SetCost sets the max cost of the execution.\nfunc (rt *RunTime) SetCost(cost int64) {\n\trt.cost = cost\n}\n\nfunc (rt *RunTime) SubCost(cost int64) error {\n\tif cost > 0 {\n\t\trt.cost -= cost\n\t}\n\tif rt.cost < 0 {\n\t\treturn fmt.Errorf(\"runtime cost limit overflow\")\n\t}\n\treturn nil\n}\n\n// Cost return the remain cost of the execution.\nfunc (rt *RunTime) Cost() int64 {\n\treturn rt.cost\n}\n\n// SetVMError sets error of VM\nfunc SetVMError(eType string, eText any) error {\n\terrText := fmt.Sprintf(`%v`, eText)\n\tif len(errText) > MaxErrLen {\n\t\terrText = errText[:MaxErrLen] + `...`\n\t}\n\tout, err := json.Marshal(&VMError{Type: eType, Error: errText})\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marshalling VMError\")\n\t\tout = []byte(`{\"type\": \"panic\", \"error\": \"marshalling VMError\"}`)\n\t}\n\treturn fmt.Errorf(string(out))\n}\n\nfunc (rt *RunTime) getResultValue(item mapItem) (value any, err error) {\n\tswitch item.Type {\n\tcase mapConst:\n\t\tvalue = item.Value\n\tcase mapExtend:\n\t\tvar ok bool\n\t\tvalue, ok = rt.extend[item.Value.(string)]\n\t\tif !ok {\n\t\t\trt.vm.logger.WithFields(log.Fields{\"cmd\": item.Value}).Error(\"unknown extend identifier\")\n\t\t\terr = fmt.Errorf(`unknown extend identifier %s`, item.Value)\n\t\t}\n\tcase mapVar:\n\t\tivar := item.Value.(*VarInfo)\n\t\tvar i int\n\t\tfor i = len(rt.blocks) - 1; i >= 0; i-- {\n\t\t\tif ivar.Owner == rt.blocks[i].Block {\n\t\t\t\tvalue = rt.vars[rt.blocks[i].Offset+ivar.Obj.GetVariable().Index]\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif i < 0 {\n\t\t\terr = fmt.Errorf(eWrongVar, ivar.Obj.Value)\n\t\t}\n\tcase mapMap:\n\t\tvalue, err = rt.getResultMap(item.Value.(*types.Map))\n\tcase mapArray:\n\t\tvalue, err = rt.getResultArray(item.Value.([]mapItem))\n\t}\n\treturn\n}\n\nfunc (rt *RunTime) getResultArray(cmd []mapItem) ([]any, error) {\n\tinitArr := make([]any, 0)\n\tfor _, val := range cmd {\n\t\tvalue, err := rt.getResultValue(val)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinitArr = append(initArr, value)\n\t}\n\treturn initArr, nil\n}\n\nfunc (rt *RunTime) getResultMap(cmd *types.Map) (*types.Map, error) {\n\tinitMap := types.NewMap()\n\tfor _, key := range cmd.Keys() {\n\t\tval, _ := cmd.Get(key)\n\t\tvalue, err := rt.getResultValue(val.(mapItem))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tinitMap.Set(key, value)\n\t}\n\treturn initMap, nil\n}\n\nfunc isSelfAssignment(dest, value any) bool {\n\tif _, ok := value.([]any); !ok {\n\t\tif _, ok = value.(*types.Map); !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\tif reflect.ValueOf(dest).Pointer() == reflect.ValueOf(value).Pointer() {\n\t\treturn true\n\t}\n\tswitch v := value.(type) {\n\tcase []any:\n\t\tfor _, item := range v {\n\n\t\t\tif isSelfAssignment(dest, item) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\tcase *types.Map:\n\t\tfor _, item := range v.Values() {\n\t\t\tif isSelfAssignment(dest, item) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// RunCode executes CodeBlock\nfunc (rt *RunTime) RunCode(block *CodeBlock) (status int, err error) {\n\tvar cmd *ByteCode\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = errors.Errorf(`runtime run code crashed: %v`, r)\n\t\t}\n\t\tif err != nil && !strings.HasPrefix(err.Error(), `{`) {\n\t\t\tvar curContract, line string\n\t\t\tif block.isParentContract() {\n\t\t\t\tstack := block.Parent.GetContractInfo()\n\t\t\t\tcurContract = stack.Name\n\t\t\t}\n\t\t\tif stack, ok := rt.extend[Extend_stack].([]any); ok {\n\t\t\t\tcurContract = stack[len(stack)-1].(string)\n\t\t\t}\n\n\t\t\tline = \"]\"\n\t\t\tif cmd != nil {\n\t\t\t\tline = fmt.Sprintf(\":%d]\", cmd.Line)\n\t\t\t}\n\n\t\t\tif len(rt.errInfo.Name) > 0 && rt.errInfo.Name != `ExecContract` {\n\t\t\t\terr = fmt.Errorf(\"%s [%s %s%s\", err, rt.errInfo.Name, curContract, line)\n\t\t\t\trt.errInfo.Name = ``\n\t\t\t} else {\n\t\t\t\tout := err.Error()\n\t\t\t\tif strings.HasSuffix(out, `]`) {\n\t\t\t\t\tprev := strings.LastIndexByte(out, ' ')\n\t\t\t\t\tif strings.HasPrefix(out[prev+1:], curContract+`:`) {\n\t\t\t\t\t\tout = out[:prev+1]\n\t\t\t\t\t} else {\n\t\t\t\t\t\tout = out[:len(out)-1] + ` `\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tout += ` [`\n\t\t\t\t}\n\t\t\t\terr = fmt.Errorf(`%s%s%s`, out, curContract, line)\n\t\t\t}\n\t\t}\n\t}()\n\ttop := make([]any, 8)\n\trt.blocks = append(rt.blocks, &blockStack{Block: block, Offset: len(rt.vars)})\n\tvar namemap map[string][]any\n\tif block.Type == ObjectType_Func && block.GetFuncInfo().Names != nil {\n\t\tif rt.peek() != nil {\n\t\t\tnamemap = rt.peek().(map[string][]any)\n\t\t}\n\t\trt.resetByIdx(rt.len() - 1)\n\t}\n\tstart := rt.len()\n\tvaroff := len(rt.vars)\n\tfor vkey, vpar := range block.Vars {\n\t\tif err = rt.SubCost(1); err != nil {\n\t\t\tbreak\n\t\t}\n\t\tvar value any\n\t\tif block.Type == ObjectType_Func && vkey < len(block.GetFuncInfo().Params) {\n\t\t\tvalue = rt.stack[start-len(block.GetFuncInfo().Params)+vkey]\n\t\t} else {\n\t\t\tvalue = reflect.New(vpar).Elem().Interface()\n\t\t\tif vpar == reflect.TypeOf(&types.Map{}) {\n\t\t\t\tvalue = types.NewMap()\n\t\t\t} else if vpar == reflect.TypeOf([]any{}) {\n\t\t\t\tvalue = make([]any, 0, len(rt.vars)+1)\n\t\t\t}\n\t\t}\n\t\trt.addVar(value)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\tif namemap != nil {\n\t\tfor key, item := range namemap {\n\t\t\tparams := (*block.GetFuncInfo().Names)[key]\n\t\t\tfor i, value := range item {\n\t\t\t\tif params.Variadic && i >= len(params.Params)-1 {\n\t\t\t\t\toff := varoff + params.Offset[len(params.Params)-1]\n\t\t\t\t\trt.setVar(off, append(rt.vars[off].([]any), value))\n\t\t\t\t} else {\n\t\t\t\t\trt.setVar(varoff+params.Offset[i], value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif block.Type == ObjectType_Func {\n\t\tstart -= len(block.GetFuncInfo().Params)\n\t}\n\tvar (\n\t\tassign []*VarInfo\n\t\ttmpInt int64\n\t\ttmpDec decimal.Decimal\n\t)\n\tlabels := make([]int, 0)\nmain:\n\tfor ci := 0; ci < len(block.Code); ci++ {\n\t\tif err = rt.SubCost(1); err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif rt.timeLimit {\n\t\t\terr = ErrVMTimeLimit\n\t\t\tbreak\n\t\t}\n\n\t\tif rt.mem > memoryLimit {\n\t\t\trt.vm.logger.WithFields(log.Fields{\"type\": consts.VMError}).Warn(ErrMemoryLimit)\n\t\t\terr = ErrMemoryLimit\n\t\t\tbreak\n\t\t}\n\n\t\tcmd = block.Code[ci]\n\t\tvar bin any\n\t\tsize := rt.len()\n\t\tif size < int(cmd.Cmd>>8) {\n\t\t\trt.vm.logger.WithFields(log.Fields{\"type\": consts.VMError}).Error(\"stack is empty\")\n\t\t\terr = fmt.Errorf(`stack is empty`)\n\t\t\tbreak\n\t\t}\n\t\tfor i := 1; i <= int(cmd.Cmd>>8); i++ {\n\t\t\ttop[i-1] = rt.stack[size-i]\n\t\t}\n\t\tswitch cmd.Cmd {\n\t\tcase cmdPush:\n\t\t\trt.push(cmd.Value)\n\t\tcase cmdPushStr:\n\t\t\trt.push(cmd.Value.(string))\n\t\tcase cmdIf:\n\t\t\tif valueToBool(rt.peek()) {\n\t\t\t\tstatus, err = rt.RunCode(cmd.Value.(*CodeBlock))\n\t\t\t}\n\t\tcase cmdElse:\n\t\t\tif !valueToBool(rt.peek()) {\n\t\t\t\tstatus, err = rt.RunCode(cmd.Value.(*CodeBlock))\n\t\t\t}\n\t\tcase cmdWhile:\n\t\t\tval := rt.peek()\n\t\t\trt.resetByIdx(rt.len() - 1)\n\t\t\tif valueToBool(val) {\n\t\t\t\tstatus, err = rt.RunCode(cmd.Value.(*CodeBlock))\n\t\t\t\tnewci := labels[len(labels)-1]\n\t\t\t\tlabels = labels[:len(labels)-1]\n\t\t\t\tif status == statusContinue {\n\t\t\t\t\tci = newci - 1\n\t\t\t\t\tstatus = statusNormal\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif status == statusBreak {\n\t\t\t\t\tstatus = statusNormal\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase cmdLabel:\n\t\t\tlabels = append(labels, ci)\n\t\tcase cmdContinue:\n\t\t\tstatus = statusContinue\n\t\tcase cmdBreak:\n\t\t\tstatus = statusBreak\n\t\tcase cmdAssignVar:\n\t\t\tassign = cmd.Value.([]*VarInfo)\n\t\tcase cmdAssign:\n\t\t\tcount := len(assign)\n\t\t\tfor ivar, item := range assign {\n\t\t\t\tval := rt.stack[rt.len()-count+ivar]\n\t\t\t\tif item.Owner == nil {\n\t\t\t\t\tif item.Obj.Type == ObjectType_ExtVar {\n\t\t\t\t\t\tvar n = item.Obj.GetExtendVariable().Name\n\t\t\t\t\t\tif isSysVar(n) {\n\t\t\t\t\t\t\terr = fmt.Errorf(eSysVar, n)\n\t\t\t\t\t\t\trt.vm.logger.WithError(err).Error(\"modifying system variable\")\n\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif v, ok := rt.extend[n]; ok && v != nil && reflect.TypeOf(v) != reflect.TypeOf(val) {\n\t\t\t\t\t\t\terr = fmt.Errorf(\"$%s (type %s) cannot be represented by the type %s\", n, reflect.TypeOf(val), reflect.TypeOf(v))\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\trt.setExtendVar(n, val)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfor i := len(rt.blocks) - 1; i >= 0; i-- {\n\t\t\t\t\t\tif item.Owner == rt.blocks[i].Block {\n\t\t\t\t\t\t\tk := rt.blocks[i].Offset + item.Obj.GetVariable().Index\n\t\t\t\t\t\t\tswitch v := rt.blocks[i].Block.Vars[item.Obj.GetVariable().Index]; v.String() {\n\t\t\t\t\t\t\tcase Decimal:\n\t\t\t\t\t\t\t\tvar v decimal.Decimal\n\t\t\t\t\t\t\t\tv, err = ValueToDecimal(val)\n\t\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\trt.setVar(k, v)\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tif val != nil && v != reflect.TypeOf(val) {\n\t\t\t\t\t\t\t\t\terr = fmt.Errorf(\"variable '%v' (type %s) cannot be represented by the type %s\", item.Obj.GetVariable().Name, reflect.TypeOf(val), v)\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\trt.setVar(k, val)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase cmdReturn:\n\t\t\tstatus = statusReturn\n\t\tcase cmdError:\n\t\t\teType := msgError\n\t\t\tif cmd.Value.(uint32) == keyWarning {\n\t\t\t\teType = msgWarning\n\t\t\t} else if cmd.Value.(uint32) == keyInfo {\n\t\t\t\teType = msgInfo\n\t\t\t}\n\t\t\terr = SetVMError(eType, rt.peek())\n\t\tcase cmdFuncName:\n\t\t\tifunc := cmd.Value.(FuncNameCmd)\n\t\t\tmapoff := rt.len() - 1 - ifunc.Count\n\t\t\tif rt.stack[mapoff] == nil {\n\t\t\t\trt.stack[mapoff] = make(map[string][]any)\n\t\t\t}\n\t\t\tparams := make([]any, 0, ifunc.Count)\n\t\t\tfor i := 0; i < ifunc.Count; i++ {\n\t\t\t\tcur := rt.stack[mapoff+1+i]\n\t\t\t\tif i == ifunc.Count-1 && rt.unwrap &&\n\t\t\t\t\treflect.TypeOf(cur).String() == `[]interface {}` {\n\t\t\t\t\tparams = append(params, cur.([]any)...)\n\t\t\t\t\trt.unwrap = false\n\t\t\t\t} else {\n\t\t\t\t\tparams = append(params, cur)\n\t\t\t\t}\n\t\t\t}\n\t\t\trt.stack[mapoff].(map[string][]any)[ifunc.Name] = params\n\t\t\trt.resetByIdx(mapoff + 1)\n\t\t\tcontinue\n\t\tcase cmdCallVariadic, cmdCall:\n\t\t\tvar cost = int64(CostCall)\n\t\t\tif cmd.Value.(*ObjInfo).Type == ObjectType_ExtFunc {\n\t\t\t\tfinfo := cmd.Value.(*ObjInfo).GetExtFuncInfo()\n\t\t\t\tif rt.vm.ExtCost != nil {\n\t\t\t\t\tcost = rt.vm.ExtCost(finfo.Name)\n\t\t\t\t\tif cost == -1 {\n\t\t\t\t\t\tcost = CostCall\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err = rt.SubCost(cost); err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\terr = rt.callFunc(cmd.Cmd, cmd.Value.(*ObjInfo))\n\t\tcase cmdVar:\n\t\t\tivar := cmd.Value.(*VarInfo)\n\t\t\tvar i int\n\t\t\tfor i = len(rt.blocks) - 1; i >= 0; i-- {\n\t\t\t\tif ivar.Owner == rt.blocks[i].Block {\n\t\t\t\t\trt.push(rt.vars[rt.blocks[i].Offset+ivar.Obj.GetVariable().Index])\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif i < 0 {\n\t\t\t\trt.vm.logger.WithFields(log.Fields{\"var\": ivar.Obj.Value}).Error(\"wrong var\")\n\t\t\t\terr = fmt.Errorf(`wrong var %v`, ivar.Obj.Value)\n\t\t\t\tbreak main\n\t\t\t}\n\t\tcase cmdExtend, cmdCallExtend:\n\t\t\tif err = rt.SubCost(CostExtend); err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif val, ok := rt.extend[cmd.Value.(string)]; ok {\n\t\t\t\tif cmd.Cmd == cmdCallExtend {\n\t\t\t\t\terr = rt.extendFunc(cmd.Value.(string))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\trt.vm.logger.WithFields(log.Fields{\"error\": err, \"cmd\": cmd.Value.(string)}).Error(\"executing extended function\")\n\t\t\t\t\t\terr = fmt.Errorf(`extend function %s %s`, cmd.Value.(string), err)\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tswitch varVal := val.(type) {\n\t\t\t\t\tcase int:\n\t\t\t\t\t\tval = int64(varVal)\n\t\t\t\t\t}\n\t\t\t\t\trt.push(val)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trt.vm.logger.WithFields(log.Fields{\"cmd\": cmd.Value}).Error(\"unknown extend identifier\")\n\t\t\t\terr = fmt.Errorf(`unknown extend identifier %s`, cmd.Value.(string))\n\t\t\t}\n\t\tcase cmdIndex:\n\t\t\trv := reflect.ValueOf(rt.stack[size-2])\n\t\t\titype := reflect.TypeOf(rt.stack[size-2]).String()\n\t\t\tswitch {\n\t\t\tcase itype == `*types.Map`:\n\t\t\t\tif reflect.TypeOf(rt.getStack(size-1)).String() != `string` {\n\t\t\t\t\terr = fmt.Errorf(eMapIndex, reflect.TypeOf(rt.getStack(size-1)).String())\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tv, found := rt.stack[size-2].(*types.Map).Get(rt.getStack(size - 1).(string))\n\t\t\t\tif found {\n\t\t\t\t\trt.stack[size-2] = v\n\t\t\t\t} else {\n\t\t\t\t\trt.stack[size-2] = nil\n\t\t\t\t}\n\t\t\t\trt.resetByIdx(size - 1)\n\t\t\tcase itype[:2] == brackets:\n\t\t\t\tif reflect.TypeOf(rt.getStack(size-1)).String() != `int64` {\n\t\t\t\t\terr = fmt.Errorf(eArrIndex, reflect.TypeOf(rt.getStack(size-1)).String())\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tv := rv.Index(int(rt.getStack(size - 1).(int64)))\n\t\t\t\tif v.IsValid() {\n\t\t\t\t\trt.stack[size-2] = v.Interface()\n\t\t\t\t} else {\n\t\t\t\t\trt.stack[size-2] = nil\n\t\t\t\t}\n\t\t\t\trt.resetByIdx(size - 1)\n\t\t\tdefault:\n\t\t\t\titype := reflect.TypeOf(rt.stack[size-2]).String()\n\t\t\t\trt.vm.logger.WithFields(log.Fields{\"vm_type\": itype}).Error(\"type does not support indexing\")\n\t\t\t\terr = fmt.Errorf(`Type %s doesn't support indexing`, itype)\n\t\t\t}\n\t\tcase cmdSetIndex:\n\t\t\titype := reflect.TypeOf(rt.stack[size-3]).String()\n\t\t\tindexInfo := cmd.Value.(*IndexInfo)\n\t\t\tvar indexKey int\n\t\t\tif indexInfo.Owner != nil {\n\t\t\t\tfor i := len(rt.blocks) - 1; i >= 0; i-- {\n\t\t\t\t\tif indexInfo.Owner == rt.blocks[i].Block {\n\t\t\t\t\t\tindexKey = rt.blocks[i].Offset + indexInfo.VarOffset\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif isSelfAssignment(rt.stack[size-3], rt.getStack(size-1)) {\n\t\t\t\terr = errSelfAssignment\n\t\t\t\tbreak main\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase itype == `*types.Map`:\n\t\t\t\tif rt.stack[size-3].(*types.Map).Size() > maxMapCount {\n\t\t\t\t\terr = errMaxMapCount\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif reflect.TypeOf(rt.stack[size-2]).String() != `string` {\n\t\t\t\t\terr = fmt.Errorf(eMapIndex, reflect.TypeOf(rt.stack[size-2]).String())\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\trt.stack[size-3].(*types.Map).Set(rt.stack[size-2].(string),\n\t\t\t\t\treflect.ValueOf(rt.getStack(size-1)).Interface())\n\t\t\t\trt.resetByIdx(size - 2)\n\t\t\tcase itype[:2] == brackets:\n\t\t\t\tif reflect.TypeOf(rt.stack[size-2]).String() != `int64` {\n\t\t\t\t\terr = fmt.Errorf(eArrIndex, reflect.TypeOf(rt.stack[size-2]).String())\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tind := rt.stack[size-2].(int64)\n\t\t\t\tif strings.Contains(itype, Interface) {\n\t\t\t\t\tslice := rt.stack[size-3].([]any)\n\t\t\t\t\tif int(ind) >= len(slice) {\n\t\t\t\t\t\tif ind > maxArrayIndex {\n\t\t\t\t\t\t\terr = errMaxArrayIndex\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tslice = append(slice, make([]any, int(ind)-len(slice)+1)...)\n\t\t\t\t\t\tindexInfo := cmd.Value.(*IndexInfo)\n\t\t\t\t\t\tif indexInfo.Owner == nil { // Extend variable $varname\n\t\t\t\t\t\t\trt.extend[indexInfo.Extend] = slice\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trt.vars[indexKey] = slice\n\t\t\t\t\t\t}\n\t\t\t\t\t\trt.stack[size-3] = slice\n\t\t\t\t\t}\n\t\t\t\t\tslice[ind] = rt.getStack(size - 1)\n\t\t\t\t} else {\n\t\t\t\t\tslice := rt.getStack(size - 3).([]map[string]string)\n\t\t\t\t\tslice[ind] = rt.getStack(size - 1).(map[string]string)\n\t\t\t\t}\n\t\t\t\trt.resetByIdx(size - 2)\n\t\t\tdefault:\n\t\t\t\trt.vm.logger.WithFields(log.Fields{\"vm_type\": itype}).Error(\"type does not support indexing\")\n\t\t\t\terr = fmt.Errorf(`type %s doesn't support indexing`, itype)\n\t\t\t}\n\n\t\t\tif indexInfo.Owner == nil {\n\t\t\t\trt.recalcMemExtendVar(indexInfo.Extend)\n\t\t\t} else {\n\t\t\t\trt.recalcMemVar(indexKey)\n\t\t\t}\n\t\tcase cmdUnwrapArr:\n\t\t\tif reflect.TypeOf(rt.getStack(size-1)).String() == `[]interface {}` {\n\t\t\t\trt.unwrap = true\n\t\t\t}\n\t\tcase cmdSign:\n\t\t\tswitch top[0].(type) {\n\t\t\tcase float64:\n\t\t\t\trt.stack[size-1] = -top[0].(float64)\n\t\t\tdefault:\n\t\t\t\trt.stack[size-1] = -top[0].(int64)\n\t\t\t}\n\t\tcase cmdNot:\n\t\t\trt.stack[size-1] = !valueToBool(top[0])\n\t\tcase cmdAdd:\n\t\t\tswitch top[1].(type) {\n\t\t\tcase string:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase string:\n\t\t\t\t\tbin = top[1].(string) + top[0].(string)\n\t\t\t\tcase int64:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\tbin = tmpInt + top[0].(int64)\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) + top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase float64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase string, int64, float64:\n\t\t\t\t\tbin = top[1].(float64) + ValueToFloat(top[0])\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase int64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase string, int64:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[0]); err == nil {\n\t\t\t\t\t\tbin = top[1].(int64) + tmpInt\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) + top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif reflect.TypeOf(top[1]).String() == Decimal &&\n\t\t\t\t\treflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\tbin = top[1].(decimal.Decimal).Add(top[0].(decimal.Decimal))\n\t\t\t\t} else {\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\t}\n\t\tcase cmdSub:\n\t\t\tswitch top[1].(type) {\n\t\t\tcase string:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\tbin = tmpInt - top[0].(int64)\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) - top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase float64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase string, int64, float64:\n\t\t\t\t\tbin = top[1].(float64) - ValueToFloat(top[0])\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase int64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64, string:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[0]); err == nil {\n\t\t\t\t\t\tbin = top[1].(int64) - tmpInt\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) - top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif reflect.TypeOf(top[1]).String() == Decimal &&\n\t\t\t\t\treflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\tbin = top[1].(decimal.Decimal).Sub(top[0].(decimal.Decimal))\n\t\t\t\t} else {\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\t}\n\t\tcase cmdMul:\n\t\t\tswitch top[1].(type) {\n\t\t\tcase string:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\tbin = tmpInt * top[0].(int64)\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) * top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase float64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase string, int64, float64:\n\t\t\t\t\tbin = top[1].(float64) * ValueToFloat(top[0])\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase int64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64, string:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[0]); err == nil {\n\t\t\t\t\t\tbin = top[1].(int64) * tmpInt\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) * top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif reflect.TypeOf(top[1]).String() == Decimal &&\n\t\t\t\t\treflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\tbin = top[1].(decimal.Decimal).Mul(top[0].(decimal.Decimal))\n\t\t\t\t} else {\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\t}\n\t\tcase cmdDiv:\n\t\t\tswitch top[1].(type) {\n\t\t\tcase string:\n\t\t\t\tswitch v := top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tif v == 0 {\n\t\t\t\t\t\terr = errDivZero\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\tbin = tmpInt / v\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tif v == 0 {\n\t\t\t\t\t\terr = errDivZero\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t\tbin = ValueToFloat(top[1]) / v\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase float64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase string, int64, float64:\n\t\t\t\t\tvFloat := ValueToFloat(top[0])\n\t\t\t\t\tif vFloat == 0 {\n\t\t\t\t\t\terr = errDivZero\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t\tbin = top[1].(float64) / vFloat\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tcase int64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64, string:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[0]); err == nil {\n\t\t\t\t\t\tif tmpInt == 0 {\n\t\t\t\t\t\t\terr = errDivZero\n\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbin = top[1].(int64) / tmpInt\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tif top[0].(float64) == 0 {\n\t\t\t\t\t\terr = errDivZero\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t\tbin = ValueToFloat(top[1]) / top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif reflect.TypeOf(top[1]).String() == Decimal &&\n\t\t\t\t\treflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\tif top[0].(decimal.Decimal).Cmp(decimal.Zero) == 0 {\n\t\t\t\t\t\terr = errDivZero\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t\tbin = top[1].(decimal.Decimal).Div(top[0].(decimal.Decimal)).Floor()\n\t\t\t\t} else {\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\t}\n\t\tcase cmdAnd:\n\t\t\tbin = valueToBool(top[1]) && valueToBool(top[0])\n\t\tcase cmdOr:\n\t\t\tbin = valueToBool(top[1]) || valueToBool(top[0])\n\t\tcase cmdEqual, cmdNotEq:\n\t\t\tif top[1] == nil || top[0] == nil {\n\t\t\t\tbin = top[0] == top[1]\n\t\t\t} else {\n\t\t\t\tswitch top[1].(type) {\n\t\t\t\tcase string:\n\t\t\t\t\tswitch top[0].(type) {\n\t\t\t\t\tcase int64:\n\t\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\t\tbin = tmpInt == top[0].(int64)\n\t\t\t\t\t\t}\n\t\t\t\t\tcase float64:\n\t\t\t\t\t\tbin = ValueToFloat(top[1]) == top[0].(float64)\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif reflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\t\t\tif tmpDec, err = ValueToDecimal(top[1]); err != nil {\n\t\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbin = tmpDec.Cmp(top[0].(decimal.Decimal)) == 0\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbin = top[1].(string) == top[0].(string)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = top[1].(float64) == ValueToFloat(top[0])\n\t\t\t\tcase int64:\n\t\t\t\t\tswitch top[0].(type) {\n\t\t\t\t\tcase int64:\n\t\t\t\t\t\tbin = top[1].(int64) == top[0].(int64)\n\t\t\t\t\tcase float64:\n\t\t\t\t\t\tbin = ValueToFloat(top[1]) == top[0].(float64)\n\t\t\t\t\tdefault:\n\t\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\tcase bool:\n\t\t\t\t\tswitch top[0].(type) {\n\t\t\t\t\tcase bool:\n\t\t\t\t\t\tbin = top[1].(bool) == top[0].(bool)\n\t\t\t\t\tdefault:\n\t\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tif tmpDec, err = ValueToDecimal(top[0]); err != nil {\n\t\t\t\t\t\tbreak main\n\t\t\t\t\t}\n\t\t\t\t\tbin = top[1].(decimal.Decimal).Cmp(tmpDec) == 0\n\t\t\t\t}\n\t\t\t}\n\t\t\tif cmd.Cmd == cmdNotEq {\n\t\t\t\tbin = !bin.(bool)\n\t\t\t}\n\t\tcase cmdLess, cmdNotLess:\n\t\t\tswitch top[1].(type) {\n\t\t\tcase string:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\tbin = tmpInt < top[0].(int64)\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) < top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\tif reflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\t\tif tmpDec, err = ValueToDecimal(top[1]); err != nil {\n\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbin = tmpDec.Cmp(top[0].(decimal.Decimal)) < 0\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbin = top[1].(string) < top[0].(string)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase float64:\n\t\t\t\tbin = top[1].(float64) < ValueToFloat(top[0])\n\t\t\tcase int64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tbin = top[1].(int64) < top[0].(int64)\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) < top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif tmpDec, err = ValueToDecimal(top[0]); err != nil {\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\t\tbin = top[1].(decimal.Decimal).Cmp(tmpDec) < 0\n\t\t\t}\n\t\t\tif cmd.Cmd == cmdNotLess {\n\t\t\t\tbin = !bin.(bool)\n\t\t\t}\n\t\tcase cmdGreat, cmdNotGreat:\n\t\t\tswitch top[1].(type) {\n\t\t\tcase string:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tif tmpInt, err = converter.ValueToInt(top[1]); err == nil {\n\t\t\t\t\t\tbin = tmpInt > top[0].(int64)\n\t\t\t\t\t}\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) > top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\tif reflect.TypeOf(top[0]).String() == Decimal {\n\t\t\t\t\t\tif tmpDec, err = ValueToDecimal(top[1]); err != nil {\n\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbin = tmpDec.Cmp(top[0].(decimal.Decimal)) > 0\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbin = top[1].(string) > top[0].(string)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase float64:\n\t\t\t\tbin = top[1].(float64) > ValueToFloat(top[0])\n\t\t\tcase int64:\n\t\t\t\tswitch top[0].(type) {\n\t\t\t\tcase int64:\n\t\t\t\t\tbin = top[1].(int64) > top[0].(int64)\n\t\t\t\tcase float64:\n\t\t\t\t\tbin = ValueToFloat(top[1]) > top[0].(float64)\n\t\t\t\tdefault:\n\t\t\t\t\terr = errUnsupportedType\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif tmpDec, err = ValueToDecimal(top[0]); err != nil {\n\t\t\t\t\tbreak main\n\t\t\t\t}\n\t\t\t\tbin = top[1].(decimal.Decimal).Cmp(tmpDec) > 0\n\t\t\t}\n\t\t\tif cmd.Cmd == cmdNotGreat {\n\t\t\t\tbin = !bin.(bool)\n\t\t\t}\n\t\tcase cmdArrayInit:\n\t\t\tvar initArray []any\n\t\t\tinitArray, err = rt.getResultArray(cmd.Value.([]mapItem))\n\t\t\tif err != nil {\n\t\t\t\tbreak main\n\t\t\t}\n\t\t\trt.push(initArray)\n\t\tcase cmdMapInit:\n\t\t\tvar initMap *types.Map\n\t\t\tinitMap, err = rt.getResultMap(cmd.Value.(*types.Map))\n\t\t\tif err != nil {\n\t\t\t\tbreak main\n\t\t\t}\n\t\t\trt.push(initMap)\n\t\tdefault:\n\t\t\trt.vm.logger.WithFields(log.Fields{\"vm_cmd\": cmd.Cmd}).Error(\"Unknown command\")\n\t\t\terr = fmt.Errorf(`unknown command %d`, cmd.Cmd)\n\t\t}\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif status == statusReturn || status == statusContinue || status == statusBreak {\n\t\t\tbreak\n\t\t}\n\t\tif (cmd.Cmd >> 8) == 2 {\n\t\t\trt.stack[size-2] = bin\n\t\t\trt.resetByIdx(size - 1)\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\tlast := rt.popBlock()\n\tif status == statusReturn {\n\t\tif last.Block.Type == ObjectType_Func {\n\t\t\tlastResults := last.Block.GetFuncInfo().Results\n\t\t\tif len(lastResults) > rt.len() {\n\t\t\t\tvar keyNames []string\n\t\t\t\tfor i := 0; i < len(lastResults); i++ {\n\t\t\t\t\tkeyNames = append(keyNames, lastResults[i].String())\n\t\t\t\t}\n\t\t\t\terr = fmt.Errorf(\"func '%s' not enough arguments to return, need [%s]\", last.Block.GetFuncInfo().Name, strings.Join(keyNames, \"|\"))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tstackCpy := make([]any, rt.len())\n\t\t\tcopy(stackCpy, rt.stack)\n\t\t\tvar index int\n\t\t\tfor count := len(lastResults); count > 0; count-- {\n\t\t\t\tval := stackCpy[len(stackCpy)-1-index]\n\t\t\t\tif val != nil && lastResults[count-1] != reflect.TypeOf(val) {\n\t\t\t\t\terr = fmt.Errorf(\"function '%s' return index[%d] (type %s) cannot be represented by the type %s\", last.Block.GetFuncInfo().Name, count-1, reflect.TypeOf(val), lastResults[count-1])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\trt.stack[start] = rt.stack[rt.len()-count]\n\t\t\t\tstart++\n\t\t\t\tindex++\n\t\t\t}\n\t\t\tstatus = statusNormal\n\t\t} else {\n\t\t\treturn\n\t\t}\n\t}\n\n\trt.resetByIdx(start)\n\treturn\n}\n\n// Run executes CodeBlock with the specified parameters and extended variables and functions\nfunc (rt *RunTime) Run(block *CodeBlock, params []any, extend map[string]any) (ret []any, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\t//rt.vm.logger.WithFields(log.Fields{\"type\": consts.PanicRecoveredError, \"error_info\": r, \"stack\": string(debug.Stack())}).Error(\"runtime panic error\")\n\t\t\terr = fmt.Errorf(`runtime panic: %v`, r)\n\t\t}\n\t}()\n\tinfo := block.GetFuncInfo()\n\trt.extend = extend\n\tvar (\n\t\tgenBlock bool\n\t\ttimer    *time.Timer\n\t)\n\tif gen, ok := extend[Extend_gen_block]; ok {\n\t\tgenBlock = gen.(bool)\n\t}\n\ttimeOver := func() {\n\t\trt.timeLimit = true\n\t}\n\tif genBlock {\n\t\ttimer = time.AfterFunc(time.Millisecond*time.Duration(extend[Extend_time_limit].(int64)), timeOver)\n\t}\n\tif _, err = rt.RunCode(block); err == nil {\n\t\tif rt.len() < len(info.Results) {\n\t\t\tvar keyNames []string\n\t\t\tfor i := 0; i < len(info.Results); i++ {\n\t\t\t\tkeyNames = append(keyNames, info.Results[i].String())\n\t\t\t}\n\t\t\terr = fmt.Errorf(\"not enough arguments to return, need [%s]\", strings.Join(keyNames, \"|\"))\n\t\t}\n\t\toff := rt.len() - len(info.Results)\n\t\tfor i := 0; i < len(info.Results) && off >= 0; i++ {\n\t\t\tret = append(ret, rt.stack[off+i])\n\t\t}\n\t}\n\tif genBlock {\n\t\ttimer.Stop()\n\t}\n\treturn\n}\n"
  },
  {
    "path": "packages/script/runtime_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCalcMem(t *testing.T) {\n\tcases := []struct {\n\t\tv   any\n\t\tmem int64\n\t}{\n\t\t{true, 1},\n\t\t{int8(1), 1}, {int16(1), 2}, {int32(1), 4},\n\t\t{int64(1), 8}, {int(1), 8},\n\t\t{float32(1), 4}, {float64(1), 8},\n\t\t{\"test\", 4},\n\t\t{[]byte(\"test\"), 16},\n\t\t{[]string{\"test\", \"test\"}, 20},\n\t\t{map[string]string{\"test\": \"test\"}, 12},\n\t}\n\n\tfor _, v := range cases {\n\t\tassert.Equal(t, v.mem, calcMem(v.v))\n\t}\n}\n"
  },
  {
    "path": "packages/script/stack.go",
    "content": "package script\n\nfunc (rt *RunTime) Stack() []any {\n\treturn rt.stack\n}\n\nfunc (rt *RunTime) push(d any) {\n\trt.stack = append(rt.stack, d)\n}\n\nfunc (rt *RunTime) pop() (ret any) {\n\tret = rt.peek()\n\trt.stack = rt.stack[:rt.len()-1]\n\treturn\n}\n\nfunc (rt *RunTime) len() int {\n\treturn len(rt.stack)\n}\n\nfunc (rt *RunTime) swap(n int) {\n\trt.stack[rt.len()-n], rt.stack[rt.len()-1] = rt.peek(), rt.stack[rt.len()-n]\n}\n\nfunc (rt *RunTime) dup(n int) {\n\trt.push(&rt.stack[rt.len()-n])\n}\n\nfunc (rt *RunTime) peek() any {\n\treturn rt.stack[rt.len()-1]\n}\n\nfunc (rt *RunTime) getStack(idx int) any {\n\tif idx >= 0 && rt.len() > 0 && rt.len() > idx {\n\t\treturn rt.stack[idx]\n\t}\n\treturn nil\n}\n\nfunc (rt *RunTime) resetByIdx(idx int) {\n\trt.stack = rt.stack[:idx]\n}\n\nfunc (rt *RunTime) popBlock() (ret *blockStack) {\n\tret = rt.blocks[len(rt.blocks)-1]\n\trt.blocks = rt.blocks[:len(rt.blocks)-1]\n\treturn\n}\n"
  },
  {
    "path": "packages/script/state.go",
    "content": "package script\n\ntype (\n\tstateTypes int\n\tstateLine  map[int]compileState\n\t// The list of compile states\n\tcompileStates map[stateTypes]stateLine\n)\n\nconst (\n\t// The list of state types\n\tstateRoot stateTypes = iota\n\tstateBody\n\tstateBlock\n\tstateContract\n\tstateFunc\n\tstateFParams\n\tstateFParam\n\tstateFParamTYPE\n\tstateFTail\n\tstateFResult\n\tstateFDot\n\tstateVar\n\tstateVarType\n\tstateAssignEval\n\tstateAssign\n\tstateTX\n\tstateSettings\n\tstateConsts\n\tstateConstsAssign\n\tstateConstsValue\n\tstateFields\n\tstateEval\n\n\t// The list of state flags\n\tstatePush     = 0x0100\n\tstatePop      = 0x0200\n\tstateStay     = 0x0400\n\tstateToBlock  = 0x0800\n\tstateToBody   = 0x1000\n\tstateFork     = 0x2000\n\tstateToFork   = 0x4000\n\tstateLabel    = 0x8000\n\tstateMustEval = 0x010000\n\n\tflushMark = 0x100000\n)\n\nvar (\n\t// 'states' describes a finite machine with states on the base of which a bytecode will be generated\n\tstates = compileStates{\n\t\tstateRoot: { // stateRoot\n\t\t\tlexNewLine:                      newCompileState(stateRoot, cfNothing),\n\t\t\tlexKeyword | (keyContract << 8): newCompileState(stateContract|statePush, cfNothing),\n\t\t\tlexKeyword | (keyFunc << 8):     newCompileState(stateFunc|statePush, cfNothing),\n\t\t\tlexUnknown:                      newCompileState(errUnknownCmd, cfError),\n\t\t},\n\t\tstateBody: { // stateBody\n\t\t\tlexNewLine:                      newCompileState(stateBody, cfNothing),\n\t\t\tlexKeyword | (keyFunc << 8):     newCompileState(stateFunc|statePush, cfNothing),\n\t\t\tlexKeyword | (keyReturn << 8):   newCompileState(stateEval, cfReturn),\n\t\t\tlexKeyword | (keyContinue << 8): newCompileState(stateBody, cfContinue),\n\t\t\tlexKeyword | (keyBreak << 8):    newCompileState(stateBody, cfBreak),\n\t\t\tlexKeyword | (keyIf << 8):       newCompileState(stateEval|statePush|stateToBlock|stateMustEval, cfIf),\n\t\t\tlexKeyword | (keyWhile << 8):    newCompileState(stateEval|statePush|stateToBlock|stateLabel|stateMustEval, cfWhile),\n\t\t\tlexKeyword | (keyElse << 8):     newCompileState(stateBlock|statePush, cfElse),\n\t\t\tlexKeyword | (keyVar << 8):      newCompileState(stateVar, cfNothing),\n\t\t\tlexKeyword | (keyTX << 8):       newCompileState(stateTX, cfTX),\n\t\t\tlexKeyword | (keySettings << 8): newCompileState(stateSettings, cfSettings),\n\t\t\tlexKeyword | (keyError << 8):    newCompileState(stateEval, cfCmdError),\n\t\t\tlexKeyword | (keyWarning << 8):  newCompileState(stateEval, cfCmdError),\n\t\t\tlexKeyword | (keyInfo << 8):     newCompileState(stateEval, cfCmdError),\n\t\t\tlexIdent:                        newCompileState(stateAssignEval|stateFork, cfNothing),\n\t\t\tlexExtend:                       newCompileState(stateAssignEval|stateFork, cfNothing),\n\t\t\tisRCurly:                        newCompileState(statePop, cfNothing),\n\t\t\tlexUnknown:                      newCompileState(errMustRCurly, cfError),\n\t\t},\n\t\tstateBlock: { // stateBlock\n\t\t\tlexNewLine: newCompileState(stateBlock, cfNothing),\n\t\t\tisLCurly:   newCompileState(stateBody, cfNothing),\n\t\t\tlexUnknown: newCompileState(errMustLCurly, cfError),\n\t\t},\n\t\tstateContract: { // stateContract\n\t\t\tlexNewLine: newCompileState(stateContract, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateBlock, cfNameBlock),\n\t\t\tlexUnknown: newCompileState(errMustName, cfError),\n\t\t},\n\t\tstateFunc: { // stateFunc\n\t\t\tlexNewLine: newCompileState(stateFunc, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateFParams, cfNameBlock),\n\t\t\tlexUnknown: newCompileState(errMustName, cfError),\n\t\t},\n\t\tstateFParams: { // stateFParams\n\t\t\tlexNewLine: newCompileState(stateFParams, cfNothing),\n\t\t\tisLPar:     newCompileState(stateFParam, cfNothing),\n\t\t\tlexUnknown: newCompileState(stateFResult|stateStay, cfNothing),\n\t\t},\n\t\tstateFParam: { // stateFParam\n\t\t\tlexNewLine: newCompileState(stateFParam, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateFParamTYPE, cfFParam),\n\t\t\t//lexType:  newCompileState(stateFParam, cfFType),\n\t\t\tisComma:    newCompileState(stateFParam, cfNothing),\n\t\t\tisRPar:     newCompileState(stateFResult, cfNothing),\n\t\t\tlexUnknown: newCompileState(errParams, cfError),\n\t\t},\n\t\tstateFParamTYPE: { // stateFParamTYPE\n\t\t\tlexIdent:                    newCompileState(stateFParamTYPE, cfFParam),\n\t\t\tlexType:                     newCompileState(stateFParam, cfFType),\n\t\t\tlexKeyword | (keyTail << 8): newCompileState(stateFTail, cfFTail),\n\t\t\tisComma:                     newCompileState(stateFParamTYPE, cfNothing),\n\t\t\t//\t\t\tisRPar:  newCompileState(stateFResult, Func: cfNothing),\n\t\t\tlexUnknown: newCompileState(errVarType, cfError),\n\t\t},\n\t\tstateFTail: { // stateFTail\n\t\t\tlexNewLine: newCompileState(stateFTail, cfNothing),\n\t\t\tisRPar:     newCompileState(stateFResult, cfNothing),\n\t\t\tlexUnknown: newCompileState(errParams, cfError),\n\t\t},\n\t\tstateFResult: { // stateFResult\n\t\t\tlexNewLine: newCompileState(stateFResult, cfNothing),\n\t\t\tisDot:      newCompileState(stateFDot, cfNothing),\n\t\t\tlexType:    newCompileState(stateFResult, cfFResult),\n\t\t\tisComma:    newCompileState(stateFResult, cfNothing),\n\t\t\tlexUnknown: newCompileState(stateBlock|stateStay, cfNothing),\n\t\t},\n\t\tstateFDot: { // stateFDot\n\t\t\tlexNewLine: newCompileState(stateFDot, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateFParams, cfFNameParam),\n\t\t\tlexUnknown: newCompileState(errMustName, cfError),\n\t\t},\n\t\tstateVar: { // stateVar\n\t\t\tlexNewLine: newCompileState(stateBody, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateVarType, cfFParam),\n\t\t\tisRCurly:   newCompileState(stateBody|stateStay, cfNothing),\n\t\t\tisComma:    newCompileState(stateVar, cfNothing),\n\t\t\tlexUnknown: newCompileState(errVars, cfError),\n\t\t},\n\t\tstateVarType: { // stateVarType\n\t\t\tlexIdent:   newCompileState(stateVarType, cfFParam),\n\t\t\tlexType:    newCompileState(stateVar, cfFType),\n\t\t\tisComma:    newCompileState(stateVarType, cfNothing),\n\t\t\tlexUnknown: newCompileState(errVarType, cfError),\n\t\t},\n\t\tstateAssignEval: { // stateAssignEval\n\t\t\tisLPar:     newCompileState(stateEval|stateToFork|stateToBody, cfNothing),\n\t\t\tisLBrack:   newCompileState(stateEval|stateToFork|stateToBody, cfNothing),\n\t\t\tlexUnknown: newCompileState(stateAssign|stateToFork|stateStay, cfNothing),\n\t\t},\n\t\tstateAssign: { // stateAssign\n\t\t\tisComma:    newCompileState(stateAssign, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateAssign, cfAssignVar),\n\t\t\tlexExtend:  newCompileState(stateAssign, cfAssignVar),\n\t\t\tisEq:       newCompileState(stateEval|stateToBody, cfAssign),\n\t\t\tlexUnknown: newCompileState(errAssign, cfError),\n\t\t},\n\t\tstateTX: { // stateTX\n\t\t\tlexNewLine: newCompileState(stateTX, cfNothing),\n\t\t\tisLCurly:   newCompileState(stateFields, cfNothing),\n\t\t\t//lexIdent:   newCompileState(stateAssign, cfTX), //todo\n\t\t\tlexExtend:  newCompileState(stateAssign, cfTX), //todo\n\t\t\tlexUnknown: newCompileState(errMustLCurly, cfError),\n\t\t},\n\t\tstateSettings: { // stateSettings\n\t\t\tlexNewLine: newCompileState(stateSettings, cfNothing),\n\t\t\tisLCurly:   newCompileState(stateConsts, cfNothing),\n\t\t\tlexUnknown: newCompileState(errMustLCurly, cfError),\n\t\t},\n\t\tstateConsts: { // stateConsts\n\t\t\tlexNewLine: newCompileState(stateConsts, cfNothing),\n\t\t\tisComma:    newCompileState(stateConsts, cfNothing),\n\t\t\tlexIdent:   newCompileState(stateConstsAssign, cfConstName),\n\t\t\tisRCurly:   newCompileState(stateToBody, cfNothing),\n\t\t\tlexUnknown: newCompileState(errMustRCurly, cfError),\n\t\t},\n\t\tstateConstsAssign: { // stateConstsAssign\n\t\t\tisEq:       newCompileState(stateConstsValue, cfNothing),\n\t\t\tlexUnknown: newCompileState(errAssign, cfError),\n\t\t},\n\t\tstateConstsValue: { // stateConstsValue\n\t\t\tlexString:  newCompileState(stateConsts, cfConstValue),\n\t\t\tlexNumber:  newCompileState(stateConsts, cfConstValue),\n\t\t\tlexUnknown: newCompileState(errStrNum, cfError),\n\t\t},\n\t\tstateFields: { // stateFields\n\t\t\tlexNewLine: newCompileState(stateFields, cfFieldLine),\n\t\t\tisComma:    newCompileState(stateFields, cfFieldComma),\n\t\t\tlexIdent:   newCompileState(stateFields, cfField),\n\t\t\tlexType:    newCompileState(stateFields, cfFieldType),\n\t\t\tlexString:  newCompileState(stateFields, cfFieldTag),\n\t\t\tisRCurly:   newCompileState(stateToBody, cfFields),\n\t\t\tlexUnknown: newCompileState(errMustRCurly, cfError),\n\t\t},\n\t}\n)\n"
  },
  {
    "path": "packages/script/vm.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage script\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype GlobalVm struct {\n\tmu      sync.Mutex\n\tsmartVM *VM\n}\n\nfunc init() {\n\t_vm = newVM()\n}\n\nvar (\n\t_vm *GlobalVm\n)\n\nfunc newVM() *GlobalVm {\n\tvm := NewVM()\n\treturn &GlobalVm{\n\t\tsmartVM: vm,\n\t}\n}\n\n// GetVM is returning smart vm\nfunc GetVM() *VM {\n\t_vm.mu.Lock()\n\tdefer _vm.mu.Unlock()\n\treturn _vm.smartVM\n}\n\nvar smartObjects map[string]*ObjInfo\nvar children uint32\n\nfunc SavepointSmartVMObjects() {\n\tsmartObjects = make(map[string]*ObjInfo)\n\tfor k, v := range GetVM().Objects {\n\t\tsmartObjects[k] = v\n\t}\n\tchildren = uint32(len(GetVM().Children))\n}\n\nfunc RollbackSmartVMObjects() {\n\tGetVM().Objects = make(map[string]*ObjInfo)\n\tfor k, v := range smartObjects {\n\t\tGetVM().Objects[k] = v\n\t}\n\n\tGetVM().Children = GetVM().Children[:children]\n\tsmartObjects = nil\n}\n\nfunc ReleaseSmartVMObjects() {\n\tsmartObjects = nil\n\tchildren = 0\n}\n\nfunc VMCompileEval(vm *VM, src string, prefix uint32) error {\n\tvar ok bool\n\tif len(src) == 0 {\n\t\treturn nil\n\t}\n\tallowed := []string{`0`, `1`, `true`, `false`, `ContractConditions\\(\\s*\\\".*\\\"\\s*\\)`,\n\t\t`ContractAccess\\(\\s*\\\".*\\\"\\s*\\)`, `RoleAccess\\(\\s*.*\\s*\\)`}\n\tfor _, v := range allowed {\n\t\tre := regexp.MustCompile(`^` + v + `$`)\n\t\tif re.Match([]byte(src)) {\n\t\t\tok = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !ok {\n\t\treturn fmt.Errorf(eConditionNotAllowed, src)\n\t}\n\terr := vm.CompileEval(src, prefix)\n\tif err != nil {\n\t\treturn err\n\t}\n\tre := regexp.MustCompile(`^@?[\\d\\w_]+$`)\n\tfor _, item := range getContractList(src) {\n\t\tif len(item) == 0 || !re.Match([]byte(item)) {\n\t\t\treturn errIncorrectParameter\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getContractList(src string) (list []string) {\n\tfor _, funcCond := range []string{`ContractConditions`, `ContractAccess`} {\n\t\tif strings.Contains(src, funcCond) {\n\t\t\tif ret := regexp.MustCompile(funcCond +\n\t\t\t\t`\\(\\s*(.*)\\s*\\)`).FindStringSubmatch(src); len(ret) == 2 {\n\t\t\t\tfor _, item := range strings.Split(ret[1], `,`) {\n\t\t\t\t\tlist = append(list, strings.Trim(item, \"\\\"` \"))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\nfunc VMGetContractByID(vm *VM, id int32) *ContractInfo {\n\tvar tableID int64\n\tif id > consts.ShiftContractID {\n\t\ttableID = int64(id - consts.ShiftContractID)\n\t\tid = int32(tableID + vm.ShiftContract)\n\t}\n\tidcont := id\n\tif len(vm.Children) <= int(idcont) {\n\t\treturn nil\n\t}\n\tif vm.Children[idcont] == nil || vm.Children[idcont].Type != ObjectType_Contract {\n\t\treturn nil\n\t}\n\tif tableID > 0 && vm.Children[idcont].GetContractInfo().Owner.TableID != tableID {\n\t\treturn nil\n\t}\n\treturn vm.Children[idcont].GetContractInfo()\n}\n\nfunc RunContractById(vm *VM, id int32, methods []string, extend map[string]any, txHash []byte) error {\n\tinfo := VMGetContractByID(vm, id)\n\tif info == nil {\n\t\treturn fmt.Errorf(`unknown contract id '%d'`, id)\n\t}\n\treturn RunContractByName(vm, info.Name, methods, extend, txHash)\n}\n\nfunc RunContractByName(vm *VM, name string, methods []string, extend map[string]any, txHash []byte) error {\n\tobj, ok := vm.Objects[name]\n\tif !ok {\n\t\treturn fmt.Errorf(`unknown object '%s'`, name)\n\t}\n\n\tif obj.Type != ObjectType_Contract {\n\t\treturn fmt.Errorf(eUnknownContract, name)\n\t}\n\tcontract := obj.GetCodeBlock()\n\textend[Extend_txcost] = extend[Extend_txcost].(int64) - CostContract - contract.contractBaseCost()\n\tif extend[Extend_txcost].(int64) < 0 {\n\t\treturn fmt.Errorf(\"runtime cost limit overflow\")\n\t}\n\tvar err error\n\tfor i := 0; i < len(methods); i++ {\n\t\tmethod := methods[i]\n\t\tobj, ok := contract.Objects[method]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif obj.Type == ObjectType_Func {\n\t\t\tfn := obj.GetCodeBlock()\n\t\t\t_, err = VMRun(vm, fn, nil, extend, txHash)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn err\n}\n\n// VMRun executes CodeBlock in vm\nfunc VMRun(vm *VM, block *CodeBlock, params []any, extend map[string]any, hash []byte) (ret []any, err error) {\n\tif block == nil {\n\t\treturn nil, fmt.Errorf(`code block is nil`)\n\t}\n\tvar cost int64\n\tif ecost, ok := extend[Extend_txcost]; ok {\n\t\tcost = ecost.(int64)\n\t} else {\n\t\tcost = syspar.GetMaxCost()\n\t}\n\trt := NewRunTime(vm, cost)\n\tret, err = rt.Run(block, params, extend)\n\textend[Extend_txcost] = rt.Cost()\n\tif err != nil {\n\t\tvm.logger.WithFields(log.Fields{\"type\": consts.VMError, \"tx_hash\": fmt.Sprintf(\"%x\", hash), \"error\": err, \"original_contract\": extend[Extend_original_contract], \"this_contract\": extend[Extend_this_contract], \"ecosystem_id\": extend[Extend_ecosystem_id]}).Error(\"running block in smart vm\")\n\t\treturn nil, err\n\t}\n\treturn\n}\n\nfunc VMObjectExists(vm *VM, name string, state uint32) bool {\n\tname = StateName(state, name)\n\t_, ok := vm.Objects[name]\n\treturn ok\n}\n\n// SetExtendCost sets the cost of calling extended obj in vm\nfunc (vm *VM) SetExtendCost(ext func(string) int64) {\n\tvm.ExtCost = ext\n}\n\n// SetFuncCallsDB Set up functions that can edit the database in vm\nfunc (vm *VM) SetFuncCallsDB(funcCallsDB map[string]struct{}) {\n\tvm.FuncCallsDB = funcCallsDB\n}\n\nfunc LoadSysFuncs(vm *VM, state int) error {\n\tcode := `func DBFind(table string).Select(query string).Columns(columns string).Where(where map)\n\t.WhereId(id int).Order(order string).Limit(limit int).Offset(offset int).Group(group string).All(all bool) array {\n   return DBSelect(table, columns, id, order, offset, limit, where, query, group, all)\n}\n\nfunc One(list array, name string) string {\n   if list {\n\t   var row map \n\t   row = list[0]\n\t   if Contains(name, \"->\") {\n\t\t   var colfield array\n\t\t   var val string\n\t\t   colfield = Split(ToLower(name), \"->\")\n\t\t   val = row[Join(colfield, \".\")]\n\t\t   if !val && row[colfield[0]] {\n\t\t\t   var fields map\n\t\t\t   var i int\n\t\t\t   fields = JSONDecode(row[colfield[0]])\n\t\t\t   val = fields[colfield[1]]\n\t\t\t   i = 2\n\t\t\t   while i < Len(colfield) {\n\t\t\t\t\tif GetType(val) == \"map[string]interface {}\" {\n\t\t\t\t\t\tval = val[colfield[i]]\n\t\t\t\t\t\tif !val {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t  \ti= i+1\n\t\t\t\t   \t} else {\n\t\t\t\t\t\tbreak\n\t\t\t\t   \t}\n\t\t\t   }\n\t\t   }\n\t\t   if !val {\n\t\t\t   return \"\"\n\t\t   }\n\t\t   return val\n\t   }\n\t   return Str(row[name])\n   }\n   return \"\"\n}\n\nfunc Row(list array) map {\n   var ret map\n   if list {\n\t   ret = list[0]\n   }\n   return ret\n}\n\nfunc DBRow(table string).Columns(columns string).Where(where map)\n   .WhereId(id int).Order(order string) map {\n   \n   var result array\n   result = DBFind(table).Columns(columns).Where(where).WhereId(id).Order(order)\n\n   var row map\n   if Len(result) > 0 {\n\t   row = result[0]\n   }\n\n   return row\n}\n\nfunc ConditionById(table string, validate bool) {\n   var row map\n   row = DBRow(table).Columns(\"conditions\").WhereId($Id)\n   if !row[\"conditions\"] {\n\t   error Sprintf(\"Item %d has not been found\", $Id)\n   }\n\n   Eval(row[\"conditions\"])\n\n   if validate {\n\t   ValidateCondition($Conditions,$ecosystem_id)\n   }\n}\n\nfunc CurrentKeyFromAccount(account string) int {\n\tvar row map\n\trow = DBRow(\"@1keys\").Columns(\"id\").Where({\"account\": account, \"deleted\": 0})\n\tif row {\n\t\treturn row[\"id\"]\n\t}\n\treturn 0\n}`\n\treturn vm.Compile([]rune(code), &OwnerInfo{StateID: uint32(state)})\n}\n"
  },
  {
    "path": "packages/script/vm.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: vm.proto\n\npackage script\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/gogo/protobuf/proto\"\n\tmath \"math\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package\n\n// VMType is virtual machine type\ntype VMType int32\n\nconst (\n\t// VMType_INVALID is invalid type\n\tVMType_INVALID VMType = 0\n\t// VMType_Smart is smart vm type\n\tVMType_Smart VMType = 1\n\t// VMType_CLB is clb vm type\n\tVMType_CLB VMType = 2\n\t// VMType_CLBMaster is CLBMaster type\n\tVMType_CLBMaster VMType = 3\n)\n\nvar VMType_name = map[int32]string{\n\t0: \"INVALID\",\n\t1: \"Smart\",\n\t2: \"CLB\",\n\t3: \"CLBMaster\",\n}\n\nvar VMType_value = map[string]int32{\n\t\"INVALID\":   0,\n\t\"Smart\":     1,\n\t\"CLB\":       2,\n\t\"CLBMaster\": 3,\n}\n\nfunc (x VMType) String() string {\n\treturn proto.EnumName(VMType_name, int32(x))\n}\n\nfunc (VMType) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_cab246c8c7c5372d, []int{0}\n}\n\n// ObjectType Types of the compiled objects\ntype ObjectType int32\n\nconst (\n\t// ObjUnknown is an unknown object.\n\tObjectType_Unknown ObjectType = 0\n\t// ObjectType_Contract is a contract object.\n\tObjectType_Contract ObjectType = 1\n\t// ObjectType_Func is a function object. myfunc()\n\tObjectType_Func ObjectType = 2\n\t// ObjectType_ExtFunc is an extended build in function object. $myfunc()\n\tObjectType_ExtFunc ObjectType = 3\n\t// ObjectType_Var is a variable. myvar\n\tObjectType_Var ObjectType = 4\n\t// ObjectType_ExtVar is an extended build in variable. $myvar\n\tObjectType_ExtVar ObjectType = 5\n)\n\nvar ObjectType_name = map[int32]string{\n\t0: \"Unknown\",\n\t1: \"Contract\",\n\t2: \"Func\",\n\t3: \"ExtFunc\",\n\t4: \"Var\",\n\t5: \"ExtVar\",\n}\n\nvar ObjectType_value = map[string]int32{\n\t\"Unknown\":  0,\n\t\"Contract\": 1,\n\t\"Func\":     2,\n\t\"ExtFunc\":  3,\n\t\"Var\":      4,\n\t\"ExtVar\":   5,\n}\n\nfunc (x ObjectType) String() string {\n\treturn proto.EnumName(ObjectType_name, int32(x))\n}\n\nfunc (ObjectType) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_cab246c8c7c5372d, []int{1}\n}\n\nfunc init() {\n\tproto.RegisterEnum(\"script.VMType\", VMType_name, VMType_value)\n\tproto.RegisterEnum(\"script.ObjectType\", ObjectType_name, ObjectType_value)\n}\n\nfunc init() { proto.RegisterFile(\"vm.proto\", fileDescriptor_cab246c8c7c5372d) }\n\nvar fileDescriptor_cab246c8c7c5372d = []byte{\n\t// 241 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x28, 0xcb, 0xd5, 0x2b,\n\t0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2b, 0x4e, 0x2e, 0xca, 0x2c, 0x28, 0xd1, 0xb2, 0xe0, 0x62,\n\t0x0b, 0xf3, 0x0d, 0xa9, 0x2c, 0x48, 0x15, 0xe2, 0xe6, 0x62, 0xf7, 0xf4, 0x0b, 0x73, 0xf4, 0xf1,\n\t0x74, 0x11, 0x60, 0x10, 0xe2, 0xe4, 0x62, 0x0d, 0xce, 0x4d, 0x2c, 0x2a, 0x11, 0x60, 0x14, 0x62,\n\t0xe7, 0x62, 0x76, 0xf6, 0x71, 0x12, 0x60, 0x12, 0xe2, 0xe5, 0xe2, 0x74, 0xf6, 0x71, 0xf2, 0x4d,\n\t0x2c, 0x2e, 0x49, 0x2d, 0x12, 0x60, 0xd6, 0x0a, 0xe6, 0xe2, 0xf2, 0x4f, 0xca, 0x4a, 0x4d, 0x2e,\n\t0x81, 0xe9, 0x0e, 0xcd, 0xcb, 0xce, 0xcb, 0x2f, 0xcf, 0x13, 0x60, 0x10, 0xe2, 0xe1, 0xe2, 0x70,\n\t0xce, 0xcf, 0x2b, 0x29, 0x4a, 0x4c, 0x06, 0x19, 0xc0, 0xc1, 0xc5, 0xe2, 0x56, 0x9a, 0x97, 0x2c,\n\t0xc0, 0x04, 0x52, 0xe4, 0x5a, 0x51, 0x02, 0xe6, 0x30, 0x83, 0xcc, 0x0d, 0x4b, 0x2c, 0x12, 0x60,\n\t0x11, 0xe2, 0xe2, 0x62, 0x73, 0xad, 0x28, 0x01, 0xb1, 0x59, 0x9d, 0x5c, 0x4e, 0x3c, 0x92, 0x63,\n\t0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96,\n\t0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x4a, 0x2b, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39,\n\t0x3f, 0x57, 0xdf, 0xd3, 0xc9, 0x31, 0x42, 0x37, 0x33, 0x5f, 0x3f, 0x3d, 0x5f, 0x37, 0x33, 0x29,\n\t0xb1, 0x42, 0xbf, 0x20, 0x31, 0x39, 0x3b, 0x31, 0x3d, 0xb5, 0x58, 0x1f, 0xe2, 0xa9, 0x24, 0x36,\n\t0xb0, 0x1f, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x01, 0x5c, 0x7e, 0x1d, 0xef, 0x00, 0x00,\n\t0x00,\n}\n"
  },
  {
    "path": "packages/script/vminit.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage script\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\t// CostCall is the cost of the function calling\n\tCostCall = 50\n\t// CostContract is the cost of the contract calling\n\tCostContract = 100\n\t// CostExtend is the cost of the extend function calling\n\tCostExtend = 10\n\n\tTagFile      = \"file\"\n\tTagAddress   = \"address\"\n\tTagSignature = \"signature\"\n\tTagOptional  = \"optional\"\n)\n\n// ExtFuncInfo is the structure for the extended function\ntype ExtFuncInfo struct {\n\tName     string\n\tParams   []reflect.Type\n\tResults  []reflect.Type\n\tAuto     []string\n\tVariadic bool\n\tFunc     any\n\tCanWrite bool // If the function can update DB\n}\n\n// FieldInfo describes the field of the data structure\ntype FieldInfo struct {\n\tName     string\n\tType     reflect.Type\n\tOriginal uint32\n\tTags     string\n}\n\n// ContainsTag returns whether the tag is contained in this field\nfunc (fi *FieldInfo) ContainsTag(tag string) bool {\n\treturn strings.Contains(fi.Tags, tag)\n}\n\n// ContractInfo contains the contract information\ntype ContractInfo struct {\n\tID       uint32\n\tName     string\n\tOwner    *OwnerInfo\n\tUsed     map[string]bool // Called contracts\n\tTx       *[]*FieldInfo\n\tSettings map[string]any\n\tCanWrite bool // If the function can update DB\n}\n\nfunc (c *ContractInfo) TxMap() map[string]*FieldInfo {\n\tif c == nil {\n\t\treturn nil\n\t}\n\tvar m = make(map[string]*FieldInfo)\n\tfor _, n := range *c.Tx {\n\t\tm[n.Name] = nil\n\t}\n\treturn m\n}\n\n// FuncNameCmd for cmdFuncName\ntype FuncNameCmd struct {\n\tName  string\n\tCount int\n}\n\n// FuncName is storing param of FuncName\ntype FuncName struct {\n\tParams   []reflect.Type\n\tOffset   []int\n\tVariadic bool\n}\n\n// FuncInfo contains the function information\ntype FuncInfo struct {\n\tName    string\n\tParams  []reflect.Type\n\tResults []reflect.Type\n\t//tail function\n\tNames    *map[string]FuncName\n\tVariadic bool\n\tID       uint32\n\tCanWrite bool // If the function can update DB\n}\n\n// VarInfo contains the variable information\ntype VarInfo struct {\n\tObj   *ObjInfo\n\tOwner *CodeBlock\n}\n\n// IndexInfo contains the information for SetIndex\ntype IndexInfo struct {\n\tVarOffset int\n\tOwner     *CodeBlock\n\tExtend    string\n}\n\n// VM is the main type of the virtual machine\ntype VM struct {\n\t*CodeBlock\n\tExtCost       func(string) int64\n\tFuncCallsDB   map[string]struct{}\n\tExtern        bool  // extern mode of compilation\n\tShiftContract int64 // id of the first contract\n\tlogger        *log.Entry\n}\n\n// Stacker represents interface for working with call stack\ntype Stacker interface {\n\tAppendStack(fn string) error\n\tPopStack(fn string)\n}\n\n// NewVM creates a new virtual machine\nfunc NewVM() *VM {\n\tvm := &VM{\n\t\tCodeBlock:   NewCodeBlock(),\n\t\tExtern:      true,\n\t\tFuncCallsDB: make(map[string]struct{}),\n\t}\n\tvm.logger = log.WithFields(log.Fields{\"type\": consts.VMError, \"extern\": vm.Extern, \"vm_block_type\": vm.CodeBlock.Type})\n\treturn vm\n}\n\nfunc getNameByObj(obj *ObjInfo) (name string) {\n\tblock := obj.GetCodeBlock()\n\tfor key, val := range block.Parent.Objects {\n\t\tif val == obj {\n\t\t\tname = key\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\n// Call executes the name object with the specified params and extended variables and functions\nfunc (vm *VM) Call(name string, params []any, extend map[string]any) (ret []any, err error) {\n\tvar obj *ObjInfo\n\tif state, ok := extend[Extend_rt_state]; ok {\n\t\tobj = vm.getObjByNameExt(name, state.(uint32))\n\t} else {\n\t\tobj = vm.getObjByName(name)\n\t}\n\tif obj == nil {\n\t\tvm.logger.WithFields(log.Fields{\"type\": consts.VMError, \"vm_func_name\": name}).Error(\"unknown function\")\n\t\treturn nil, fmt.Errorf(`unknown function %s`, name)\n\t}\n\tswitch obj.Type {\n\tcase ObjectType_Func:\n\t\tvar cost int64\n\t\tif v, ok := extend[Extend_txcost]; ok {\n\t\t\tcost = v.(int64)\n\t\t} else {\n\t\t\tcost = syspar.GetMaxCost()\n\t\t}\n\t\trt := NewRunTime(vm, cost)\n\t\tret, err = rt.Run(obj.GetCodeBlock(), params, extend)\n\t\textend[Extend_txcost] = rt.Cost()\n\tcase ObjectType_ExtFunc:\n\t\tfinfo := obj.GetExtFuncInfo()\n\t\tfoo := reflect.ValueOf(finfo.Func)\n\t\tvar result []reflect.Value\n\t\tpars := make([]reflect.Value, len(finfo.Params))\n\t\tif finfo.Variadic {\n\t\t\tfor i := 0; i < len(pars)-1; i++ {\n\t\t\t\tpars[i] = reflect.ValueOf(params[i])\n\t\t\t}\n\t\t\tpars[len(pars)-1] = reflect.ValueOf(params[len(pars)-1:])\n\t\t\tresult = foo.CallSlice(pars)\n\t\t} else {\n\t\t\tfor i := 0; i < len(pars); i++ {\n\t\t\t\tpars[i] = reflect.ValueOf(params[i])\n\t\t\t}\n\t\t\tresult = foo.Call(pars)\n\t\t}\n\t\tfor _, iret := range result {\n\t\t\tret = append(ret, iret.Interface())\n\t\t}\n\tdefault:\n\t\tvm.logger.WithFields(log.Fields{\"type\": consts.VMError, \"vm_func_name\": name}).Error(\"unknown function\")\n\t\treturn nil, fmt.Errorf(`unknown function %s`, name)\n\t}\n\treturn ret, err\n}\n"
  },
  {
    "path": "packages/service/gateway/gateway.go",
    "content": "package gateway\n"
  },
  {
    "path": "packages/service/jsonrpc/accounts.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"net/http\"\n)\n\ntype accountsApi struct {\n\tMode\n}\n\nfunc newAccountsApi(m Mode) *accountsApi {\n\treturn &accountsApi{m}\n}\n\nfunc (c *accountsApi) GetKeysCount(ctx RequestContext) (*int64, *Error) {\n\tr := ctx.HTTPRequest()\n\tcnt, err := sqldb.GetKeysCount()\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting keys count\")\n\t\treturn nil, InternalError(err.Error())\n\t}\n\n\treturn &cnt, nil\n}\n\ntype BalanceResult struct {\n\tAmount      string `json:\"amount\"`\n\tDigits      int64  `json:\"digits\"`\n\tTotal       string `json:\"total\"`\n\tUtxo        string `json:\"utxo\"`\n\tTokenSymbol string `json:\"token_symbol\"`\n\tTokenName   string `json:\"token_name\"`\n}\n\ntype AccountOrKeyId struct {\n\tKeyId   int64  `json:\"key_id,omitempty\"`\n\tAccount string `json:\"account,omitempty\"`\n}\n\nfunc (bh *AccountOrKeyId) Validate(r *http.Request) error {\n\tif bh == nil {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\tif bh.KeyId == 0 {\n\t\treturn errors.New(\"invalid input\")\n\t}\n\n\treturn nil\n}\n\n// UnmarshalJSON verify input, keyId is preferred\nfunc (bh *AccountOrKeyId) UnmarshalJSON(data []byte) error {\n\ttype rename AccountOrKeyId\n\tinfo := rename{}\n\terr := json.Unmarshal(data, &info)\n\tif err == nil {\n\t\tif info.KeyId != 0 {\n\t\t\tif converter.IDToAddress(info.KeyId) == `invalid` {\n\t\t\t\treturn errors.New(\"invalid key id\")\n\t\t\t}\n\t\t\tbh.KeyId = info.KeyId\n\t\t\treturn nil\n\t\t}\n\t\tkeyId := converter.AddressToID(info.Account)\n\t\tif keyId == 0 {\n\t\t\treturn errors.New(\"invalid Account\")\n\t\t}\n\t\tbh.KeyId = keyId\n\t\treturn nil\n\t}\n\tvar input string\n\terr = json.Unmarshal(data, &input)\n\tif err != nil {\n\t\treturn err\n\t}\n\tkeyId := converter.AddressToID(input)\n\tif keyId == 0 {\n\t\treturn errors.New(\"invalid key id or account address\")\n\t}\n\tbh.KeyId = keyId\n\treturn nil\n}\n\nfunc (b *accountsApi) GetBalance(ctx RequestContext, info *AccountOrKeyId, ecosystemId *int64) (*BalanceResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\tform := &ecosystemForm{\n\t\tValidator: b.EcosystemGetter,\n\t}\n\tif ecosystemId != nil {\n\t\tform.EcosystemID = *ecosystemId\n\t}\n\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\tif err := parameterValidator(r, info); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\tkeyId := info.KeyId\n\n\tkey := &sqldb.Key{}\n\tkey.SetTablePrefix(form.EcosystemID)\n\t_, err := key.Get(nil, keyId)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting Key for wallet\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\taccountAmount, _ := decimal.NewFromString(key.Amount)\n\n\tsp := &sqldb.SpentInfo{}\n\tutxoAmount, err := sp.GetBalance(nil, keyId, form.EcosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting UTXO Key for wallet\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\ttotal := utxoAmount.Add(accountAmount)\n\n\teco := sqldb.Ecosystem{}\n\t_, err = eco.Get(nil, form.EcosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting key balance token symbol\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\treturn &BalanceResult{\n\t\tAmount:      key.Amount,\n\t\tDigits:      eco.Digits,\n\t\tTotal:       total.String(),\n\t\tUtxo:        utxoAmount.String(),\n\t\tTokenSymbol: eco.TokenSymbol,\n\t\tTokenName:   eco.TokenName,\n\t}, nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/api.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage jsonrpc\n\nimport (\n\t\"encoding/hex\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nconst (\n\tmultipartBuf      = 100000 // the buffer size for ParseMultipartForm\n\tmultipartFormData = \"multipart/form-data\"\n)\n\ntype Mode struct {\n\tEcosystemGetter   types.EcosystemGetter\n\tContractRunner    types.SmartContractRunner\n\tClientTxProcessor types.ClientTxPreprocessor\n}\n\ntype UserClient struct {\n\tKeyID         int64\n\tAccountID     string\n\tEcosystemID   int64\n\tEcosystemName string\n\tRoleID        int64\n}\n\nfunc (c *UserClient) Prefix() string {\n\treturn converter.Int64ToStr(c.EcosystemID)\n}\n\ntype formValidator interface {\n\tValidate(r *http.Request) error\n}\n\nfunc parameterValidator(r *http.Request, f formValidator) (err error) {\n\treturn f.Validate(r)\n}\n\nfunc isMultipartForm(r *http.Request) bool {\n\treturn strings.HasPrefix(r.Header.Get(\"Content-Type\"), multipartFormData)\n}\n\ntype hexValue struct {\n\tvalue []byte\n}\n\nfunc (hv hexValue) Bytes() []byte {\n\treturn hv.value\n}\n\nfunc (hv *hexValue) UnmarshalText(v []byte) (err error) {\n\thv.value, err = hex.DecodeString(string(v))\n\treturn\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/auth.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/publisher\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/golang-jwt/jwt/v4\"\n)\n\ntype AuthStatusResponse struct {\n\tIsActive  bool  `json:\"active\"`\n\tExpiresAt int64 `json:\"exp,omitempty\"`\n}\n\ntype Auth struct {\n\tMode\n}\n\nfunc authRequire(r *http.Request) *Error {\n\tclient := getClient(r)\n\tif client != nil && client.KeyID != 0 {\n\t\treturn nil\n\t}\n\n\tlogger := getLogger(r)\n\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Debug(\"wallet is empty\")\n\treturn UnauthorizedError()\n}\n\ntype authApi struct {\n\tmode Mode\n}\n\nfunc newAuthApi(mode Mode) *authApi {\n\ta := &authApi{\n\t\tmode: mode,\n\t}\n\treturn a\n}\n\nfunc (a *authApi) GetAuthStatus(ctx RequestContext) (*AuthStatusResponse, *Error) {\n\tresult := new(AuthStatusResponse)\n\n\tr := ctx.HTTPRequest()\n\ttoken := getToken(r)\n\tif token == nil {\n\t\treturn result, nil\n\t}\n\n\tclaims, ok := token.Claims.(*JWTClaims)\n\tif !ok {\n\t\treturn result, nil\n\t}\n\n\tresult.IsActive = true\n\tresult.ExpiresAt = claims.ExpiresAt.Unix()\n\treturn result, nil\n}\n\ntype GetUIDResult struct {\n\tUID         string `json:\"uid,omitempty\"`\n\tToken       string `json:\"token,omitempty\"`\n\tExpire      string `json:\"expire,omitempty\"`\n\tEcosystemID string `json:\"ecosystem_id,omitempty\"`\n\tKeyID       string `json:\"key_id,omitempty\"`\n\tAddress     string `json:\"address,omitempty\"`\n\tNetworkID   string `json:\"network_id,omitempty\"`\n\tCryptoer    string `json:\"cryptoer\"`\n\tHasher      string `json:\"hasher\"`\n}\n\nfunc (a *authApi) GetUid(ctx RequestContext) (*GetUIDResult, *Error) {\n\tconst jwtUIDExpire = time.Second * 5\n\n\tresult := new(GetUIDResult)\n\tresult.NetworkID = converter.Int64ToStr(conf.Config.LocalConf.NetworkID)\n\tr := ctx.HTTPRequest()\n\ttoken := getToken(r)\n\tresult.Cryptoer, result.Hasher = conf.Config.CryptoSettings.Cryptoer, conf.Config.CryptoSettings.Hasher\n\tif token != nil {\n\t\tif claims, ok := token.Claims.(*JWTClaims); ok && len(claims.KeyID) > 0 {\n\t\t\tresult.EcosystemID = claims.EcosystemID\n\t\t\tresult.Expire = claims.ExpiresAt.Sub(time.Now()).String()\n\t\t\tresult.KeyID = claims.KeyID\n\t\t\tresult.Address = converter.AddressToString(converter.StrToInt64(claims.KeyID))\n\t\t\treturn result, nil\n\t\t}\n\t}\n\n\tresult.UID = converter.Int64ToStr(rand.New(rand.NewSource(time.Now().Unix())).Int63())\n\tclaims := JWTClaims{\n\t\tUID:         result.UID,\n\t\tEcosystemID: \"1\",\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\tExpiresAt: &jwt.NumericDate{Time: time.Now().Add(jwtUIDExpire)},\n\t\t},\n\t}\n\n\tvar err error\n\tif result.Token, err = generateJWTToken(claims); err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JWTError, \"error\": err}).Error(\"generating jwt token\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\treturn result, nil\n}\n\n// Special word used by frontend to sign UID generated by /getuid API command, sign is performed for contcatenated word and UID\nfunc nonceSalt() string {\n\treturn fmt.Sprintf(\"LOGIN%d\", conf.Config.LocalConf.NetworkID)\n}\n\ntype loginForm struct {\n\tEcosystemID int64          `json:\"ecosystem_id\"`\n\tExpire      int64          `json:\"expire\"`\n\tPublicKey   publicKeyValue `json:\"public_key\"`\n\tKeyID       string         `json:\"key_id\"`\n\tSignature   hexValue       `json:\"signature\"`\n\tRoleID      int64          `json:\"role_id\"`\n}\n\ntype publicKeyValue struct {\n\thexValue\n}\n\nfunc (pk *publicKeyValue) UnmarshalText(v []byte) (err error) {\n\tpk.value, err = hex.DecodeString(string(v))\n\tpk.value = crypto.CutPub(pk.value)\n\treturn\n}\n\nfunc (f *loginForm) Validate(r *http.Request) error {\n\tif f == nil {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\tif f.Expire == 0 {\n\t\tf.Expire = int64(jwtExpire)\n\t}\n\n\treturn nil\n}\n\ntype LoginResult struct {\n\tToken       string        `json:\"token,omitempty\"`\n\tEcosystemID string        `json:\"ecosystem_id,omitempty\"`\n\tKeyID       string        `json:\"key_id,omitempty\"`\n\tAccount     string        `json:\"account,omitempty\"`\n\tNotifyKey   string        `json:\"notify_key,omitempty\"`\n\tIsNode      bool          `json:\"isnode\"`\n\tIsOwner     bool          `json:\"isowner\"`\n\tIsCLB       bool          `json:\"clb\"`\n\tTimestamp   string        `json:\"timestamp,omitempty\"`\n\tRoles       []rolesResult `json:\"roles,omitempty\"`\n}\n\ntype rolesResult struct {\n\tRoleID   int64  `json:\"role_id\"`\n\tRoleName string `json:\"role_name\"`\n}\n\nfunc (a authApi) Login(ctx RequestContext, form *loginForm) (*LoginResult, *Error) {\n\tvar (\n\t\tpublicKey           []byte\n\t\twallet, founder, fm int64\n\t\tisExistPub          bool\n\t\tspfounder, spfm     sqldb.StateParameter\n\t)\n\tr := ctx.HTTPRequest()\n\tuid, err := getUID(r)\n\tif err != nil {\n\t\treturn nil, UnUnknownUIDError()\n\t}\n\tif err := form.Validate(r); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tif form.EcosystemID > 0 {\n\t\tclient.EcosystemID = form.EcosystemID\n\t} else if client.EcosystemID == 0 {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Warning(\"state is empty, using 1 as a state\")\n\t\tclient.EcosystemID = 1\n\t}\n\n\tif len(form.KeyID) > 0 {\n\t\twallet = converter.StringToAddress(form.KeyID)\n\t} else if len(form.PublicKey.Bytes()) > 0 {\n\t\twallet = crypto.Address(form.PublicKey.Bytes())\n\t}\n\n\taccount := &sqldb.Key{}\n\taccount.SetTablePrefix(client.EcosystemID)\n\tisAccount, err := account.Get(nil, wallet)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tspfm.SetTablePrefix(converter.Int64ToStr(client.EcosystemID))\n\tif ok, err := spfm.Get(nil, \"free_membership\"); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting free_membership parameter\")\n\t\treturn nil, DefaultError(err.Error())\n\t} else if ok {\n\t\tfm = converter.StrToInt64(spfm.Value)\n\t}\n\tpublicKey = account.PublicKey\n\tisExistPub = len(publicKey) == 0\n\n\tisCan := func(a, e bool) bool {\n\t\treturn !a || (a && e)\n\t}\n\tif isCan(isAccount, isExistPub) {\n\t\tif !(fm == 1 || client.EcosystemID == 1) {\n\t\t\treturn nil, DefaultError(fmt.Sprintf(\"The ecosystem (%d) is not open and cannot be registered address\", client.EcosystemID))\n\t\t}\n\t}\n\n\tif isAccount && !isExistPub {\n\t\tif account.Deleted == 1 {\n\t\t\treturn nil, DefaultError(\"The key is deleted\")\n\t\t}\n\t} else {\n\t\tif !allowCreateUser(client) {\n\t\t\treturn nil, DefaultError(\"Key has not been found\")\n\t\t}\n\t\tif isCan(isAccount, isExistPub) {\n\t\t\tpublicKey = form.PublicKey.Bytes()\n\t\t\tif len(publicKey) == 0 {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty\")\n\t\t\t\treturn nil, DefaultError(\"Public key is undefined\")\n\t\t\t}\n\n\t\t\tnodePrivateKey := syspar.GetNodePrivKey()\n\n\t\t\tcontract := smart.GetContract(\"NewUser\", 1)\n\t\t\tsc := types.SmartTransaction{\n\t\t\t\tHeader: &types.Header{\n\t\t\t\t\tID:          int(contract.Info().ID),\n\t\t\t\t\tEcosystemID: 1,\n\t\t\t\t\tTime:        time.Now().Unix(),\n\t\t\t\t\tKeyID:       conf.Config.KeyID,\n\t\t\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t\t\t},\n\t\t\t\tParams: map[string]any{\n\t\t\t\t\t\"NewPubkey\": hex.EncodeToString(publicKey),\n\t\t\t\t\t\"Ecosystem\": client.EcosystemID,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tstp := &transaction.SmartTransactionParser{\n\t\t\t\tSmartContract: &smart.SmartContract{TxSmart: new(types.SmartTransaction)},\n\t\t\t}\n\t\t\ttxData, err := stp.BinMarshalWithPrivate(&sc, nodePrivateKey, true)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ContractError, \"err\": err}).Error(\"Building transaction\")\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\n\t\t\tif err := a.mode.ContractRunner.RunContract(txData, stp.Hash, sc.KeyID, stp.Timestamp, logger); err != nil {\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\n\t\t\tif !conf.Config.IsSupportingCLB() {\n\t\t\t\tgt := 3 * syspar.GetMaxBlockGenerationTime()\n\t\t\t\tl := &sqldb.LogTransaction{}\n\t\t\t\tfor i := 0; i < 2; i++ {\n\t\t\t\t\tfound, err := l.GetByHash(nil, stp.Hash)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t\t\t}\n\t\t\t\t\tif found {\n\t\t\t\t\t\tif l.Status != 0 {\n\t\t\t\t\t\t\treturn nil, DefaultError(\"encountered some problems when login account\")\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t_, _ = account.Get(nil, wallet)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(time.Duration(gt) * time.Millisecond)\n\t\t\t\t}\n\n\t\t\t\tif l.Block == 0 {\n\t\t\t\t\treturn nil, DefaultError(\"The block packing in progress, please wait\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty, and state is not default\")\n\t\t\treturn nil, DefaultError(fmt.Sprintf(\"%d is not a membership of ecosystem %d\", wallet, client.EcosystemID))\n\t\t}\n\t}\n\n\tif len(publicKey) == 0 {\n\t\tif client.EcosystemID > 1 {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty, and state is not default\")\n\t\t\treturn nil, DefaultError(fmt.Sprintf(\"%d is not a membership of ecosystem %d\", wallet, client.EcosystemID))\n\t\t}\n\n\t\tif len(form.PublicKey.Bytes()) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public key is empty\")\n\t\t\treturn nil, DefaultError(\"Public key is undefined\")\n\t\t}\n\t}\n\n\tif form.RoleID != 0 && client.RoleID == 0 {\n\t\tcheckedRole, err := checkRoleFromParam(form.RoleID, client.EcosystemID, account.AccountID)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\n\t\tif checkedRole != form.RoleID {\n\t\t\treturn nil, DefaultError(\"Access denied\")\n\t\t}\n\n\t\tclient.RoleID = checkedRole\n\t}\n\n\tverify, err := crypto.Verify(publicKey, []byte(nonceSalt()+uid), form.Signature.Bytes())\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.CryptoError, \"pubkey\": publicKey, \"uid\": uid, \"signature\": form.Signature.Bytes()}).Info(\"checking signature\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tif !verify {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.InvalidObject, \"pubkey\": publicKey, \"uid\": uid, \"signature\": form.Signature.Bytes()}).Error(\"incorrect signature\")\n\t\treturn nil, DefaultError(\"Signature is incorrect\")\n\t}\n\n\tspfounder.SetTablePrefix(converter.Int64ToStr(client.EcosystemID))\n\tif ok, err := spfounder.Get(nil, \"founder_account\"); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting founder_account parameter\")\n\t\treturn nil, DefaultError(err.Error())\n\t} else if ok {\n\t\tfounder = converter.StrToInt64(spfounder.Value)\n\t}\n\n\tresult := &LoginResult{\n\t\tAccount:     account.AccountID,\n\t\tEcosystemID: converter.Int64ToStr(client.EcosystemID),\n\t\tKeyID:       converter.Int64ToStr(wallet),\n\t\tIsOwner:     founder == wallet,\n\t\tIsNode:      conf.Config.KeyID == wallet,\n\t\tIsCLB:       conf.Config.IsSupportingCLB(),\n\t}\n\n\tclaims := JWTClaims{\n\t\tKeyID:       result.KeyID,\n\t\tAccountID:   account.AccountID,\n\t\tEcosystemID: result.EcosystemID,\n\t\tRoleID:      converter.Int64ToStr(form.RoleID),\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\tExpiresAt: &jwt.NumericDate{Time: time.Now().Add(time.Second * time.Duration(form.Expire))},\n\t\t},\n\t}\n\n\tresult.Token, err = generateJWTToken(claims)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JWTError, \"error\": err}).Error(\"generating jwt token\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tresult.NotifyKey, result.Timestamp, err = publisher.GetJWTCent(wallet, form.Expire)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tra := &sqldb.RolesParticipants{}\n\troles, err := ra.SetTablePrefix(client.EcosystemID).GetActiveMemberRoles(account.AccountID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting roles\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tfor _, r := range roles {\n\t\tvar res map[string]string\n\t\tif err := json.Unmarshal([]byte(r.Role), &res); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling role\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\n\t\tresult.Roles = append(result.Roles, rolesResult{\n\t\t\tRoleID:   converter.StrToInt64(res[\"id\"]),\n\t\t\tRoleName: res[\"name\"],\n\t\t})\n\t}\n\n\treturn result, nil\n}\n\nfunc getUID(r *http.Request) (string, error) {\n\tvar uid string\n\n\ttoken := getToken(r)\n\tif token != nil {\n\t\tif claims, ok := token.Claims.(*JWTClaims); ok {\n\t\t\tuid = claims.UID\n\t\t}\n\t} else if len(uid) == 0 {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Warning(\"UID is empty\")\n\t\treturn \"\", errors.New(\"unknown uid\")\n\t}\n\n\treturn uid, nil\n}\n\nfunc checkRoleFromParam(role, ecosystemID int64, account string) (int64, error) {\n\tif role > 0 {\n\t\tok, err := sqldb.MemberHasRole(nil, role, ecosystemID, account)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\"type\":      consts.DBError,\n\t\t\t\t\"account\":   account,\n\t\t\t\t\"role\":      role,\n\t\t\t\t\"ecosystem\": ecosystemID}).Error(\"check role\")\n\n\t\t\treturn 0, err\n\t\t}\n\n\t\tif !ok {\n\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\"type\":      consts.NotFound,\n\t\t\t\t\"account\":   account,\n\t\t\t\t\"role\":      role,\n\t\t\t\t\"ecosystem\": ecosystemID,\n\t\t\t}).Error(\"member hasn't role\")\n\n\t\t\treturn 0, nil\n\t\t}\n\t}\n\treturn role, nil\n}\n\nfunc allowCreateUser(c *UserClient) bool {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn true\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/common\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"gorm.io/gorm\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype blockChainApi struct {\n}\n\nfunc newBlockChainApi() *blockChainApi {\n\treturn &blockChainApi{}\n}\n\nfunc (b *blockChainApi) MaxBlockId(ctx RequestContext) (*int64, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tbk := &sqldb.BlockChain{}\n\tfound, err := bk.GetMaxBlock()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting max block\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"last block not found\")\n\t\treturn nil, NotFoundError()\n\t}\n\n\treturn &bk.ID, nil\n}\n\ntype BlockInfoResult struct {\n\tHash          string `json:\"hash\"`\n\tEcosystemID   int64  `json:\"ecosystem_id\"`\n\tKeyID         int64  `json:\"key_id\"`\n\tTime          int64  `json:\"time\"`\n\tTx            int32  `json:\"tx_count\"`\n\tRollbacksHash string `json:\"rollbacks_hash\"`\n\tNodePosition  int64  `json:\"node_position\"`\n\tConsensusMode int32  `json:\"consensus_mode\"`\n}\n\nfunc (b *blockChainApi) GetBlockInfo(blockID int64) (*BlockInfoResult, *Error) {\n\tbk := sqldb.BlockChain{}\n\tfound, err := bk.Get(blockID)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !found {\n\t\treturn nil, NotFoundError()\n\t}\n\n\tresult := &BlockInfoResult{\n\t\tHash:          hex.EncodeToString(bk.Hash),\n\t\tEcosystemID:   bk.EcosystemID,\n\t\tKeyID:         bk.KeyID,\n\t\tTime:          bk.Time,\n\t\tTx:            bk.Tx,\n\t\tRollbacksHash: hex.EncodeToString(bk.RollbacksHash),\n\t\tNodePosition:  bk.NodePosition,\n\t\tConsensusMode: bk.ConsensusMode,\n\t}\n\n\treturn result, nil\n}\n\nfunc (b *blockChainApi) HonorNodesCount() (*int64, *Error) {\n\tcount := syspar.GetNumberOfNodesFromDB(nil)\n\treturn &count, nil\n}\n\ntype AppParamsForm struct {\n\tecosystemForm\n\tparamsForm\n\tpaginatorForm\n}\n\nfunc (f *AppParamsForm) Validate(r *http.Request) error {\n\tif f == nil {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\terr := f.ecosystemForm.Validate(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn f.paginatorForm.Validate(r)\n}\n\ntype AppParamsResult struct {\n\tApp  int64         `json:\"app_id\"`\n\tList []ParamResult `json:\"list\"`\n}\n\nfunc (b *blockChainApi) AppParams(ctx RequestContext, auth Auth, appId int64, ecosystem *int64, names *string, offset, limit *int) (*AppParamsResult, *Error) {\n\tform := &AppParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: auth.EcosystemGetter,\n\t\t},\n\t}\n\tif ecosystem != nil {\n\t\tform.EcosystemID = *ecosystem\n\t}\n\tif names != nil {\n\t\tform.AcceptNames(*names)\n\t}\n\tif offset != nil {\n\t\tform.Offset = *offset\n\t}\n\tif limit != nil {\n\t\tform.Limit = *limit\n\t}\n\n\tr := ctx.HTTPRequest()\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tlogger := getLogger(r)\n\n\tap := &sqldb.AppParam{}\n\tap.SetTablePrefix(form.EcosystemPrefix)\n\n\tlist, err := ap.GetAllAppParameters(appId, &form.Offset, &form.Limit, form.Names)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting all app parameters\")\n\t}\n\n\tresult := &AppParamsResult{\n\t\tApp:  appId,\n\t\tList: make([]ParamResult, 0),\n\t}\n\n\tfor _, item := range list {\n\t\tresult.List = append(result.List, ParamResult{\n\t\t\tID:         converter.Int64ToStr(item.ID),\n\t\t\tName:       item.Name,\n\t\t\tValue:      item.Value,\n\t\t\tConditions: item.Conditions,\n\t\t})\n\t}\n\n\treturn result, nil\n}\n\ntype AppContentResult struct {\n\tSnippets  []sqldb.Snippet  `json:\"snippets\"`\n\tPages     []sqldb.Page     `json:\"pages\"`\n\tContracts []sqldb.Contract `json:\"contracts\"`\n}\n\nfunc (b *blockChainApi) GetAppContent(ctx RequestContext, auth Auth, appId int64) (*AppContentResult, *Error) {\n\tform := &AppParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: auth.EcosystemGetter,\n\t\t},\n\t}\n\tr := ctx.HTTPRequest()\n\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, ParseError(err.Error())\n\t}\n\n\tlogger := getLogger(r)\n\n\tsni := &sqldb.Snippet{}\n\tp := &sqldb.Page{}\n\tc := &sqldb.Contract{}\n\tecosystemID := converter.StrToInt64(form.EcosystemPrefix)\n\n\tsnippets, err := sni.GetByApp(appId, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting block interfaces by appID\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tpages, err := p.GetByApp(appId, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting pages by appID\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tcontracts, err := c.GetByApp(appId, ecosystemID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting pages by appID\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\treturn &AppContentResult{\n\t\tSnippets:  snippets,\n\t\tPages:     pages,\n\t\tContracts: contracts,\n\t}, nil\n}\n\n// History Returns the change record for the entry in the specified data table in the current ecosystem\nfunc (b *blockChainApi) History(ctx RequestContext, auth Auth, tableName string, tableId uint64) (*HistoryResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\n\tif tableName == \"\" || tableId <= 0 {\n\t\treturn nil, InvalidParamsError(\"invalid params\")\n\t}\n\n\ttable := client.Prefix() + \"_\" + tableName\n\trollbackTx := &sqldb.RollbackTx{}\n\ttxs, err := rollbackTx.GetRollbackTxsByTableIDAndTableName(strconv.FormatUint(tableId, 10), table, rollbackHistoryLimit)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"rollback history\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif txs == nil || len(*txs) == 0 {\n\t\treturn nil, NotFoundError()\n\t}\n\trollbackList := make([]map[string]string, 0, len(*txs))\n\tfor _, tx := range *txs {\n\t\tif tx.Data == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\trollback := map[string]string{}\n\t\tif err := json.Unmarshal([]byte(tx.Data), &rollback); err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling rollbackTx.Data from JSON\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\trollbackList = append(rollbackList, rollback)\n\t}\n\n\treturn &HistoryResult{rollbackList}, nil\n}\n\ntype blocksTxInfoForm struct {\n\tBlockID int64 `json:\"block_id\"`\n\tCount   int64 `json:\"count\"`\n}\n\nfunc (f *blocksTxInfoForm) Validate(r *http.Request) error {\n\tif f.BlockID <= 0 {\n\t\treturn errors.New(fmt.Sprintf(invalidParams, strconv.FormatInt(f.BlockID, 10)))\n\t}\n\tif f.BlockID > 0 {\n\t\tf.BlockID--\n\t}\n\tif f.Count <= 0 {\n\t\tf.Count = defaultPaginatorLimit\n\t}\n\n\tif f.Count > maxPaginatorLimit {\n\t\tf.Count = maxPaginatorLimit\n\t}\n\treturn nil\n}\n\ntype TxInfo struct {\n\tHash         string         `json:\"hash\"`\n\tContractName string         `json:\"contract_name\"`\n\tParams       map[string]any `json:\"params\"`\n\tKeyID        int64          `json:\"key_id\"`\n}\n\nfunc (b *blockChainApi) GetBlocksTxInfo(ctx RequestContext, blockId, count int64) (*map[int64][]TxInfo, *Error) {\n\tr := ctx.HTTPRequest()\n\tform := &blocksTxInfoForm{\n\t\tBlockID: blockId,\n\t\tCount:   count,\n\t}\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tlogger := getLogger(r)\n\n\tblocks, err := sqldb.GetBlockchain(form.BlockID, form.BlockID+form.Count, sqldb.OrderASC)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting blocks range\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tif len(blocks) == 0 {\n\t\treturn nil, NotFoundError()\n\t}\n\n\tresult := map[int64][]TxInfo{}\n\tfor _, blockModel := range blocks {\n\t\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(blockModel.Data), false)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err, \"bolck_id\": blockModel.ID}).Error(\"on unmarshalling block\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\n\t\ttxInfoCollection := make([]TxInfo, 0, len(blck.Transactions))\n\t\tfor _, tx := range blck.Transactions {\n\t\t\ttxInfo := TxInfo{\n\t\t\t\tHash: hex.EncodeToString(tx.Hash()),\n\t\t\t}\n\n\t\t\tif tx.IsSmartContract() {\n\t\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\t\ttxInfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t\t}\n\t\t\t\ttxInfo.Params = tx.SmartContract().TxData\n\t\t\t}\n\n\t\t\tif blck.IsGenesis() {\n\t\t\t\ttxInfo.KeyID = blck.Header.KeyId\n\t\t\t} else {\n\t\t\t\ttxInfo.KeyID = tx.KeyID()\n\t\t\t}\n\n\t\t\ttxInfoCollection = append(txInfoCollection, txInfo)\n\n\t\t\tlogger.WithFields(log.Fields{\"block_id\": blockModel.ID, \"tx hash\": txInfo.Hash, \"contract_name\": txInfo.ContractName, \"key_id\": txInfo.KeyID, \"params\": txInfoCollection}).Debug(\"BlockChain Transactions Information\")\n\t\t}\n\n\t\tresult[blockModel.ID] = txInfoCollection\n\t}\n\n\treturn &result, nil\n}\n\ntype TxDetailedInfo struct {\n\tHash         string         `json:\"hash\"`\n\tContractName string         `json:\"contract_name\"`\n\tParams       map[string]any `json:\"params\"`\n\tKeyID        int64          `json:\"key_id\"`\n\tTime         int64          `json:\"time\"`\n\tType         byte           `json:\"type\"`\n\tSize         string         `json:\"size\"`\n}\n\ntype BlockHeaderInfo struct {\n\tBlockID      int64  `json:\"block_id\"`\n\tTime         int64  `json:\"time\"`\n\tEcosystemID  int64  `json:\"-\"`\n\tKeyID        int64  `json:\"key_id\"`\n\tNodePosition int64  `json:\"node_position\"`\n\tSign         []byte `json:\"-\"`\n\tHash         string `json:\"-\"`\n\tVersion      int    `json:\"version\"`\n}\n\ntype BlockDetailedInfo struct {\n\tHeader        BlockHeaderInfo  `json:\"header\"`\n\tHash          string           `json:\"hash\"`\n\tEcosystemID   int64            `json:\"-\"`\n\tNodePosition  int64            `json:\"node_position\"`\n\tKeyID         int64            `json:\"key_id\"`\n\tTime          int64            `json:\"time\"`\n\tTx            int32            `json:\"tx_count\"`\n\tSize          string           `json:\"size\"`\n\tRollbacksHash string           `json:\"rollbacks_hash\"`\n\tMerkleRoot    string           `json:\"merkle_root\"`\n\tBinData       string           `json:\"bin_data\"`\n\tSysUpdate     bool             `json:\"-\"`\n\tGenBlock      bool             `json:\"-\"`\n\tStopCount     int              `json:\"stop_count\"`\n\tTransactions  []TxDetailedInfo `json:\"transactions\"`\n}\n\nfunc (b *blockChainApi) DetailedBlocks(ctx RequestContext, blockId, count int64) (*map[int64]BlockDetailedInfo, *Error) {\n\tr := ctx.HTTPRequest()\n\n\tform := &blocksTxInfoForm{\n\t\tBlockID: blockId,\n\t\tCount:   count,\n\t}\n\tif err := form.Validate(r); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tlogger := getLogger(r)\n\n\tblocks, err := sqldb.GetBlockchain(form.BlockID, form.BlockID+form.Count, sqldb.OrderASC)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting blocks range\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tif len(blocks) == 0 {\n\t\treturn nil, NotFoundError()\n\t}\n\n\tresult := map[int64]BlockDetailedInfo{}\n\tfor _, blockModel := range blocks {\n\t\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(blockModel.Data), false)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err, \"block_id\": blockModel.ID}).Error(\"on unmarshalling block\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\n\t\ttxDetailedInfoCollection := make([]TxDetailedInfo, 0, len(blck.Transactions))\n\t\tfor _, tx := range blck.Transactions {\n\t\t\ttxDetailedInfo := TxDetailedInfo{\n\t\t\t\tHash:  hex.EncodeToString(tx.Hash()),\n\t\t\t\tKeyID: tx.KeyID(),\n\t\t\t\tTime:  tx.Timestamp(),\n\t\t\t\tType:  tx.Type(),\n\t\t\t\tSize:  common.StorageSize(len(tx.Payload())).TerminalString(),\n\t\t\t}\n\n\t\t\tif tx.IsSmartContract() {\n\t\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\t\ttxDetailedInfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t\t}\n\t\t\t\ttxDetailedInfo.Params = tx.SmartContract().TxData\n\t\t\t\tif tx.Type() == types.TransferSelfTxType {\n\t\t\t\t\ttxDetailedInfo.Params = make(map[string]any)\n\t\t\t\t\ttxDetailedInfo.Params[\"TransferSelf\"] = tx.SmartContract().TxSmart.TransferSelf\n\t\t\t\t}\n\t\t\t\tif tx.Type() == types.UtxoTxType {\n\t\t\t\t\ttxDetailedInfo.Params = make(map[string]any)\n\t\t\t\t\ttxDetailedInfo.Params[\"UTXO\"] = tx.SmartContract().TxSmart.UTXO\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttxDetailedInfoCollection = append(txDetailedInfoCollection, txDetailedInfo)\n\n\t\t\tlogger.WithFields(log.Fields{\"block_id\": blockModel.ID, \"tx hash\": txDetailedInfo.Hash,\n\t\t\t\t\"contract_name\": txDetailedInfo.ContractName, \"key_id\": txDetailedInfo.KeyID,\n\t\t\t\t\"time\": txDetailedInfo.Time, \"type\": txDetailedInfo.Type,\n\t\t\t\t\"params\": txDetailedInfoCollection}).Debug(\"BlockChain Transactions Information\")\n\t\t}\n\n\t\theader := BlockHeaderInfo{\n\t\t\tBlockID:      blck.Header.BlockId,\n\t\t\tTime:         blck.Header.Timestamp,\n\t\t\tEcosystemID:  blck.Header.EcosystemId,\n\t\t\tKeyID:        blck.Header.KeyId,\n\t\t\tNodePosition: blck.Header.NodePosition,\n\t\t\tSign:         blck.Header.Sign,\n\t\t\tHash:         hex.EncodeToString(blck.Header.BlockHash),\n\t\t\tVersion:      int(blck.Header.Version),\n\t\t}\n\n\t\tbdi := BlockDetailedInfo{\n\t\t\tHeader:        header,\n\t\t\tHash:          hex.EncodeToString(blockModel.Hash),\n\t\t\tEcosystemID:   blockModel.EcosystemID,\n\t\t\tNodePosition:  blockModel.NodePosition,\n\t\t\tKeyID:         blockModel.KeyID,\n\t\t\tTime:          blockModel.Time,\n\t\t\tTx:            blockModel.Tx,\n\t\t\tRollbacksHash: hex.EncodeToString(blockModel.RollbacksHash),\n\t\t\tMerkleRoot:    hex.EncodeToString(blck.MerkleRoot),\n\t\t\tBinData:       hex.EncodeToString(blck.BinData),\n\t\t\tSize:          common.StorageSize(len(blockModel.Data)).TerminalString(),\n\t\t\tSysUpdate:     blck.SysUpdate,\n\t\t\tGenBlock:      blck.GenBlock,\n\t\t\tTransactions:  txDetailedInfoCollection,\n\t\t}\n\t\tresult[blockModel.ID] = bdi\n\t}\n\n\treturn &result, nil\n}\n\ntype BlockIdOrHash struct {\n\tId     int64  `json:\"id,omitempty\"`\n\tHash   string `json:\"hash,omitempty\"`\n\tisHash bool\n}\n\nfunc (bh *BlockIdOrHash) GetHash() ([]byte, bool) {\n\tif bh.Hash != \"\" {\n\t\thash, err := hex.DecodeString(bh.Hash)\n\t\tif err != nil {\n\t\t\treturn nil, false\n\t\t}\n\t\treturn hash, true\n\t}\n\treturn nil, false\n}\n\nfunc (bh *BlockIdOrHash) GetBlock() (int64, bool) {\n\tif bh.Id > 0 {\n\t\treturn bh.Id, true\n\t}\n\treturn 0, false\n}\n\nfunc (bh *BlockIdOrHash) Validate(r *http.Request) error {\n\tif bh == nil {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\t_, f1 := bh.GetHash()\n\t_, f2 := bh.GetBlock()\n\tif !f1 && !f2 {\n\t\treturn errors.New(fmt.Sprintf(invalidParams, \"block Id Or block Hash\"))\n\t}\n\tif f1 {\n\t\tbh.isHash = f1\n\t}\n\treturn nil\n}\n\nfunc (bh *BlockIdOrHash) UnmarshalJSON(data []byte) error {\n\ttype rename BlockIdOrHash\n\tinfo := rename{}\n\terr := json.Unmarshal(data, &info)\n\tif err == nil {\n\t\tif info.Id != 0 && info.Hash != \"\" {\n\t\t\treturn fmt.Errorf(\"block id or block hash must be only choose one\")\n\t\t}\n\t\tbh.Id = info.Id\n\t\tbh.Hash = info.Hash\n\t\treturn nil\n\t}\n\tvar input string\n\terr = json.Unmarshal(data, &input)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(input) == 64 {\n\t\tbh.Hash = input\n\t\treturn nil\n\t} else {\n\t\tif !smart.CheckNumberChars(input) {\n\t\t\treturn errors.New(\"invalid block id or block hash\")\n\t\t}\n\n\t\tblockNum, err := strconv.ParseInt(input, 10, 64)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbh.Id = blockNum\n\t\treturn nil\n\t}\n}\n\nfunc (b *blockChainApi) DetailedBlock(ctx RequestContext, bh *BlockIdOrHash) (*BlockDetailedInfo, *Error) {\n\tr := ctx.HTTPRequest()\n\n\terr := parameterValidator(r, bh)\n\tif err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\tlogger := getLogger(r)\n\n\tbk := &sqldb.BlockChain{}\n\tvar f bool\n\tif bh.isHash {\n\t\thash, _ := bh.GetHash()\n\t\tf, err = bk.GetByHash(hash)\n\t} else {\n\t\tf, err = bk.Get(bh.Id)\n\t}\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !f {\n\t\treturn nil, NotFoundError()\n\t}\n\n\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(bk.Data), false)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err, \"block_id\": bk.ID}).Error(\"on unmarshalling block\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\ttxDetailedInfoCollection := make([]TxDetailedInfo, 0, len(blck.Transactions))\n\tfor _, tx := range blck.Transactions {\n\t\ttxDetailedInfo := TxDetailedInfo{\n\t\t\tHash:  hex.EncodeToString(tx.Hash()),\n\t\t\tKeyID: tx.KeyID(),\n\t\t\tTime:  tx.Timestamp(),\n\t\t\tType:  tx.Type(),\n\t\t\tSize:  common.StorageSize(len(tx.Payload())).TerminalString(),\n\t\t}\n\n\t\tif tx.IsSmartContract() {\n\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\ttxDetailedInfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t}\n\t\t\ttxDetailedInfo.Params = tx.SmartContract().TxData\n\t\t\tif tx.Type() == types.TransferSelfTxType {\n\t\t\t\ttxDetailedInfo.Params = make(map[string]any)\n\t\t\t\ttxDetailedInfo.Params[\"TransferSelf\"] = tx.SmartContract().TxSmart.TransferSelf\n\t\t\t}\n\t\t\tif tx.Type() == types.UtxoTxType {\n\t\t\t\ttxDetailedInfo.Params = make(map[string]any)\n\t\t\t\ttxDetailedInfo.Params[\"UTXO\"] = tx.SmartContract().TxSmart.UTXO\n\t\t\t}\n\t\t}\n\n\t\ttxDetailedInfoCollection = append(txDetailedInfoCollection, txDetailedInfo)\n\n\t\tlogger.WithFields(log.Fields{\"block_id\": bk.ID, \"tx hash\": txDetailedInfo.Hash,\n\t\t\t\"contract_name\": txDetailedInfo.ContractName, \"key_id\": txDetailedInfo.KeyID,\n\t\t\t\"time\": txDetailedInfo.Time, \"type\": txDetailedInfo.Type,\n\t\t\t\"params\": txDetailedInfoCollection}).Debug(\"[GetBlock]BlockChain Transactions Information\")\n\t}\n\n\theader := BlockHeaderInfo{\n\t\tBlockID:      blck.Header.BlockId,\n\t\tTime:         blck.Header.Timestamp,\n\t\tEcosystemID:  blck.Header.EcosystemId,\n\t\tKeyID:        blck.Header.KeyId,\n\t\tNodePosition: blck.Header.NodePosition,\n\t\tSign:         blck.Header.Sign,\n\t\tHash:         hex.EncodeToString(blck.Header.BlockHash),\n\t\tVersion:      int(blck.Header.Version),\n\t}\n\n\tresult := BlockDetailedInfo{\n\t\tHeader:        header,\n\t\tHash:          hex.EncodeToString(bk.Hash),\n\t\tEcosystemID:   bk.EcosystemID,\n\t\tNodePosition:  bk.NodePosition,\n\t\tKeyID:         bk.KeyID,\n\t\tTime:          bk.Time,\n\t\tTx:            bk.Tx,\n\t\tRollbacksHash: hex.EncodeToString(bk.RollbacksHash),\n\t\tMerkleRoot:    hex.EncodeToString(blck.MerkleRoot),\n\t\tBinData:       hex.EncodeToString(blck.BinData),\n\t\tSize:          common.StorageSize(len(bk.Data)).TerminalString(),\n\t\tSysUpdate:     blck.SysUpdate,\n\t\tGenBlock:      blck.GenBlock,\n\t\tTransactions:  txDetailedInfoCollection,\n\t}\n\n\treturn &result, nil\n}\n\nfunc (b *blockChainApi) GetTransactionCount(ctx RequestContext, bh *BlockIdOrHash) (*int32, *Error) {\n\tr := ctx.HTTPRequest()\n\n\terr := parameterValidator(r, bh)\n\tif err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tbk := &sqldb.BlockChain{}\n\tvar f bool\n\tif bh.isHash {\n\t\thash, _ := bh.GetHash()\n\t\tf, err = bk.GetByHash(hash)\n\t} else {\n\t\tf, err = bk.Get(bh.Id)\n\t}\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !f {\n\t\treturn nil, NotFoundError()\n\t}\n\n\treturn &bk.Tx, nil\n}\n\nfunc (b *blockChainApi) GetEcosystemParams(ctx RequestContext, auth Auth, ecosystem *int64, names *string, offset, limit *int) (*ParamsResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tform := &AppParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: auth.EcosystemGetter,\n\t\t}}\n\tif ecosystem != nil {\n\t\tform.EcosystemID = *ecosystem\n\t}\n\tif names != nil {\n\t\tform.AcceptNames(*names)\n\t}\n\tif limit != nil {\n\t\tform.Limit = *limit\n\t}\n\tif offset != nil {\n\t\tform.Offset = *offset\n\t}\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tlogger := getLogger(r)\n\n\tsp := &sqldb.StateParameter{}\n\tsp.SetTablePrefix(form.EcosystemPrefix)\n\tlist, err := sp.GetAllStateParameters(&form.Offset, &form.Limit, form.Names)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting all state parameters\")\n\t}\n\n\tresult := &ParamsResult{\n\t\tList: make([]ParamResult, 0),\n\t}\n\n\tfor _, item := range list {\n\t\tresult.List = append(result.List, ParamResult{\n\t\t\tID:         converter.Int64ToStr(item.ID),\n\t\t\tName:       item.Name,\n\t\t\tValue:      item.Value,\n\t\t\tConditions: item.Conditions,\n\t\t})\n\t}\n\n\treturn result, nil\n}\n\ntype EcosystemInfo struct {\n\tId           int64  `json:\"id\"`\n\tName         string `json:\"name\"`\n\tDigits       int64  `json:\"digits\"`\n\tTokenSymbol  string `json:\"token_symbol\"`\n\tTokenName    string `json:\"token_name\"`\n\tTotalAmount  string `json:\"total_amount\"`\n\tIsWithdraw   bool   `json:\"is_withdraw\"`\n\tWithdraw     string `json:\"withdraw\"`\n\tIsEmission   bool   `json:\"is_emission\"`\n\tEmission     string `json:\"emission\"`\n\tIntroduction string `json:\"introduction\"`\n\tLogo         int64  `json:\"logo\"`\n\tCreator      string `json:\"creator\"`\n}\n\nvar totalSupplyToken = decimal.New(2100000000, int32(consts.MoneyDigits))\n\nfunc (b *blockChainApi) EcosystemInfo(ctx RequestContext, ecosystemId int64) (*EcosystemInfo, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tpara := &sqldb.StateParameter{}\n\tpara.SetTablePrefix(strconv.FormatInt(ecosystemId, 10))\n\tf, err := para.Get(nil, \"founder_account\")\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !f {\n\t\treturn nil, NotFoundError()\n\t}\n\n\teco := &sqldb.Ecosystem{}\n\tfound, err := eco.Get(nil, ecosystemId)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting ecosystem name\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"ecosystem_id\": ecosystemId}).Debug(\"ecosystem by id not found\")\n\t\treturn nil, NotFoundError()\n\t}\n\n\tinfo := &EcosystemInfo{}\n\tkeyId, err := strconv.ParseInt(para.Value, 10, 64)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"creator:\": para.Value}).Debug(\"get Ecosystem Creator Failed\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\ttype emsAmount struct {\n\t\tVal  decimal.Decimal `json:\"val\"`\n\t\tTime string          `json:\"time\"`\n\t\tType string          `json:\"type\"`\n\t}\n\tvar emissionAmount []emsAmount\n\ttotal := decimal.New(0, 0)\n\twithdraw := decimal.New(0, 0)\n\temission := decimal.New(0, 0)\n\tif eco.EmissionAmount != \"\" {\n\t\tinfo := eco.EmissionAmount\n\t\tif err := json.Unmarshal([]byte(info), &emissionAmount); err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tfor _, v := range emissionAmount {\n\t\t\tswitch v.Type {\n\t\t\tcase \"issue\":\n\t\t\t\ttotal = total.Add(v.Val)\n\t\t\tcase \"emission\":\n\t\t\t\temission = emission.Add(v.Val)\n\t\t\tcase \"burn\":\n\t\t\t\twithdraw = withdraw.Add(v.Val)\n\t\t\t}\n\t\t}\n\t}\n\tif eco.Info != \"\" {\n\t\tminfo := make(map[string]any)\n\t\terr := json.Unmarshal([]byte(eco.Info), &minfo)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err}).Error(\"Get Ecosystem Info Failed\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tlogo, ok := minfo[\"logo\"]\n\t\tif ok {\n\t\t\tlogoId, err := strconv.ParseInt(strings.Replace(fmt.Sprint(logo), `'`, `''`, -1), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\t\t\tinfo.Logo = logoId\n\t\t}\n\t\tfor k, v := range minfo {\n\t\t\tswitch k {\n\t\t\tcase \"description\":\n\t\t\t\tinfo.Introduction = fmt.Sprint(v)\n\t\t\t}\n\t\t}\n\t}\n\n\tinfo.Creator = converter.AddressToString(keyId)\n\tinfo.Id = eco.ID\n\tinfo.Name = eco.Name\n\tinfo.TokenSymbol = eco.TokenSymbol\n\tinfo.TokenName = eco.TokenName\n\tinfo.Digits = eco.Digits\n\tif eco.TypeWithdraw == 1 {\n\t\tinfo.IsWithdraw = true\n\t}\n\tif eco.TypeEmission == 1 {\n\t\tinfo.IsEmission = true\n\t}\n\tinfo.Withdraw = withdraw.String()\n\tinfo.Emission = emission.String()\n\tif info.Id == 1 {\n\t\tinfo.TotalAmount = totalSupplyToken.String()\n\t\treturn info, nil\n\t}\n\tinfo.TotalAmount = total.String()\n\n\treturn info, nil\n}\n\nfunc (b *blockChainApi) SystemParams(ctx RequestContext, auth Auth, names *string, offset, limit *int) (*ParamsResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tform := &AppParamsForm{\n\t\tecosystemForm: ecosystemForm{\n\t\t\tValidator: auth.EcosystemGetter,\n\t\t},\n\t}\n\tif names != nil {\n\t\tform.AcceptNames(*names)\n\t}\n\tif offset != nil {\n\t\tform.Offset = *offset\n\t}\n\tif limit != nil {\n\t\tform.Limit = *limit\n\t}\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tlogger := getLogger(r)\n\n\tlist, err := sqldb.GetAllPlatformParameters(nil, &form.Offset, &form.Limit, form.Names)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting all platform parameters\")\n\t}\n\n\tresult := &ParamsResult{\n\t\tList: make([]ParamResult, 0),\n\t}\n\n\tfor _, item := range list {\n\t\tresult.List = append(result.List, ParamResult{\n\t\t\tID:         converter.Int64ToStr(item.ID),\n\t\t\tName:       item.Name,\n\t\t\tValue:      item.Value,\n\t\t\tConditions: item.Conditions,\n\t\t})\n\t}\n\n\tif len(result.List) == 0 {\n\t\treturn nil, NotFoundError()\n\t}\n\n\treturn result, nil\n}\n\ntype MemberInfo struct {\n\tID         int64  `json:\"id\"`\n\tMemberName string `json:\"member_name\"`\n\tImageID    *int64 `json:\"image_id\"`\n\tMemberInfo string `json:\"member_info\"`\n}\n\nfunc (b *blockChainApi) GetMember(ctx RequestContext, account string, ecosystemId int64) (*MemberInfo, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tkeyId := converter.AddressToID(account)\n\tif keyId == 0 {\n\t\treturn nil, InvalidParamsError(fmt.Sprintf(\"account[%s] address invalid\", account))\n\t}\n\tif ecosystemId <= 0 {\n\t\treturn nil, InvalidParamsError(fmt.Sprintf(\"ecosystem id invalid\"))\n\t}\n\n\tmember := &sqldb.Member{}\n\tmember.SetTablePrefix(converter.Int64ToStr(ecosystemId))\n\n\t_, err := member.Get(account)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\n\t\t\t\"type\":      consts.DBError,\n\t\t\t\"error\":     err,\n\t\t\t\"ecosystem\": ecosystemId,\n\t\t\t\"account\":   account,\n\t\t}).Error(\"getting member\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tinfo := &MemberInfo{\n\t\tID:         member.ID,\n\t\tMemberName: member.MemberName,\n\t\tImageID:    member.ImageID,\n\t\tMemberInfo: member.MemberInfo,\n\t}\n\n\treturn info, nil\n}\n\ntype ListWhereForm struct {\n\tListForm\n\tOrder any `json:\"order\"`\n\tWhere any `json:\"where\"`\n}\n\nfunc (f *ListWhereForm) Validate(r *http.Request) error {\n\tif f == nil || f.Name == \"\" {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\treturn f.ListForm.Validate(r)\n}\n\ntype blockMetricByNode struct {\n\tTotalCount   int64 `json:\"total_count\"`\n\tPartialCount int64 `json:\"partial_count\"`\n}\n\nfunc (b *blockChainApi) GetBlocksCountByNode(ctx RequestContext, nodePosition int64, consensusMode int32) (*blockMetricByNode, *Error) {\n\tif nodePosition < 0 || consensusMode <= 0 || (consensusMode != consts.CandidateNodeMode && consensusMode != consts.HonorNodeMode) {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\tbk := &sqldb.BlockChain{}\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tfound, err := bk.GetMaxBlock()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"on getting max block\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tif !found {\n\t\treturn nil, NotFoundError()\n\t}\n\n\tc, err := sqldb.GetBlockCountByNode(nodePosition, consensusMode)\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting block count by node\")\n\t\treturn nil, InternalError(err.Error())\n\t}\n\n\tbm := blockMetricByNode{TotalCount: bk.ID, PartialCount: c}\n\n\treturn &bm, nil\n\n}\n\ntype openSystemInfo struct {\n\tEcosystem int64          `json:\"ecosystem\"`\n\tInfo      *EcosystemInfo `json:\"info,omitempty\"`\n}\n\ntype openSystemList struct {\n\tCount int64            `json:\"count\"`\n\tList  []openSystemInfo `json:\"list\"`\n}\n\n// GetOpenEcosystem\n// verbosity Type: numeric, optional, default=1\n// 1 for a ecosystem id list, and 2 for json object with ecosystem info\nfunc (b *blockChainApi) GetOpenEcosystem(ctx RequestContext, verbosity, offset, limit *int) (*openSystemList, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\tform := &paginatorForm{}\n\tif offset != nil {\n\t\tform.Offset = *offset\n\t}\n\tif limit != nil {\n\t\tform.Limit = *limit\n\t}\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tvar bosity = 1\n\tif verbosity != nil {\n\t\tbosity = *verbosity\n\t\tif bosity != 1 && bosity != 2 {\n\t\t\treturn nil, DefaultError(\"Not Supported verbosity\")\n\t\t}\n\t}\n\tvar (\n\t\tidList   []int64\n\t\tspfm     sqldb.StateParameter\n\t\tinfo     openSystemList\n\t\tsqlQuery *gorm.DB\n\t)\n\tsqlQuery = sqldb.GetDB(nil).Table(spfm.TableName()).Where(\"name = 'free_membership' AND value = '1'\").\n\t\tSelect(\"ecosystem\")\n\terr := sqlQuery.Count(&info.Count).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"get open ecosystem count\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\terr = sqlQuery.Offset(form.Offset).Limit(form.Limit).Order(\"ecosystem asc\").Find(&idList).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"get open ecosystem\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tinfo.List = make([]openSystemInfo, len(idList))\n\tfor i, ecosystem := range idList {\n\t\tif bosity == 2 {\n\t\t\tvar er *Error\n\t\t\tinfo.List[i].Info, er = b.EcosystemInfo(ctx, ecosystem)\n\t\t\tif er != nil {\n\t\t\t\treturn nil, er\n\t\t\t}\n\t\t}\n\t\tinfo.List[i].Ecosystem = ecosystem\n\t}\n\n\treturn &info, nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/callback.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"unicode\"\n)\n\nvar (\n\terrorType     = reflect.TypeOf((*Error)(nil)).Elem()\n\tcontextType   = reflect.TypeOf((*RequestContext)(nil)).Elem()\n\tauthType      = reflect.TypeOf((*Auth)(nil)).Elem()\n\tnotSingleType = reflect.TypeOf((*NotSingle)(nil)).Elem()\n)\n\ntype callback struct {\n\tfn        reflect.Value  // the function\n\trecv      reflect.Value  // receiver object of function\n\targTypes  []reflect.Type // params types\n\thasCtx    bool           // method's first argument is a RequestContext (not included in argTypes)\n\terrIndex  int            // err return index, of 0 when method cannot return error\n\thasAuth   bool           // has auth\n\tnotSingle bool\n}\n\nfunc (c *callback) getArgsTypes() {\n\tfntype := c.fn.Type()\n\t// Skip receiver and context.Context parameter (if present).\n\tfirstArg := 0\n\tif c.recv.IsValid() {\n\t\tfirstArg++\n\t}\n\tif fntype.NumIn() > firstArg && fntype.In(firstArg) == contextType {\n\t\tc.hasCtx = true\n\t\tfirstArg++\n\t}\n\tif fntype.NumIn() > firstArg && fntype.In(firstArg) == authType {\n\t\tc.hasAuth = true\n\t\tfirstArg++\n\t}\n\tif fntype.NumIn() > firstArg && fntype.In(firstArg) == notSingleType {\n\t\tc.notSingle = true\n\t\tfirstArg++\n\t}\n\t// Add all remaining parameters.\n\tc.argTypes = make([]reflect.Type, fntype.NumIn()-firstArg)\n\tfor i := firstArg; i < fntype.NumIn(); i++ {\n\t\tc.argTypes[i-firstArg] = fntype.In(i)\n\t}\n}\n\nfunc (c *callback) call(ctx RequestContext, m Mode, args []reflect.Value) (result any, errRes *Error) {\n\t// Create the argument slice.\n\tvalues := make([]reflect.Value, 0, 4+len(args))\n\tif c.recv.IsValid() {\n\t\tvalues = append(values, c.recv)\n\t}\n\tif c.hasCtx {\n\t\tvalues = append(values, reflect.ValueOf(ctx))\n\t}\n\tif c.hasAuth {\n\t\tauth := Auth{m}\n\t\tvalues = append(values, reflect.ValueOf(auth))\n\t}\n\tif c.notSingle {\n\t\tvalues = append(values, reflect.ValueOf(NotSingle{}))\n\t}\n\tvalues = append(values, args...)\n\n\t// Catch panic.\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\tconst size = 64 << 10\n\t\t\tbuf := make([]byte, size)\n\t\t\tbuf = buf[:runtime.Stack(buf, false)]\n\t\t\treq := ctx.HTTPRequest()\n\t\t\tlogger := getLogger(req)\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JsonRpcError, \"error\": err, \"buf\": string(buf)}).Error(\"RPC method \" + req.Method + \" crashed\")\n\t\t\terrRes = InternalError(\"method handler crashed\")\n\t\t}\n\t}()\n\t// call func.\n\tresults := c.fn.Call(values)\n\tif len(results) == 0 {\n\t\treturn nil, nil\n\t}\n\tif c.errIndex > 0 && !results[c.errIndex].IsNil() {\n\t\t// Method has returned non-nil error value.\n\t\terr := results[c.errIndex].Interface().(*Error)\n\t\treturn reflect.Value{}, err\n\t}\n\tk := results[0].Kind()\n\tswitch k {\n\tcase reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer, reflect.Interface, reflect.Slice:\n\t\tif results[0].IsNil() {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n\n\treturn results[0].Interface(), nil\n}\n\nfunc suitableCallbacks(receiver reflect.Value) map[string]*callback {\n\ttyp := receiver.Type()\n\tcallbacks := make(map[string]*callback)\n\tfor m := 0; m < typ.NumMethod(); m++ {\n\t\tmethod := typ.Method(m)\n\t\tif method.PkgPath != \"\" {\n\t\t\tcontinue // method not exported\n\t\t}\n\t\tcb := newCallback(receiver, method.Func)\n\t\tif cb == nil {\n\t\t\tlog.WithFields(log.Fields{\"err\": \"[json-rpv]method invalid\", \"method name\": formatName(method.Name)})\n\t\t\tcontinue // function invalid\n\t\t}\n\t\tname := formatName(method.Name)\n\t\tcallbacks[name] = cb\n\t}\n\treturn callbacks\n}\n\nfunc newCallback(receiver, fn reflect.Value) *callback {\n\tftype := fn.Type()\n\tc := &callback{fn: fn, recv: receiver, errIndex: -1}\n\t// Determine parameter types. They must all be exported or builtin types.\n\tc.getArgsTypes()\n\n\t// Verify return types. The function must return at most one error\n\t// and/or one other non-error value.\n\touts := make([]reflect.Type, ftype.NumOut())\n\tfor i := 0; i < ftype.NumOut(); i++ {\n\t\touts[i] = ftype.Out(i)\n\t}\n\tif len(outs) > 2 {\n\t\treturn nil\n\t}\n\n\tswitch {\n\t//\n\tcase len(outs) == 1 && isErrorType(outs[0]):\n\t\tc.errIndex = 0\n\t// If an error is returned, it must be the last returned value.\n\tcase len(outs) == 2:\n\t\tif isErrorType(outs[0]) || !isErrorType(outs[1]) {\n\t\t\treturn nil\n\t\t}\n\t\tc.errIndex = 1\n\t}\n\treturn c\n}\n\nfunc isErrorType(t reflect.Type) bool {\n\tfor t.Kind() == reflect.Ptr {\n\t\tt = t.Elem()\n\t}\n\t//return t.Implements(errorType) //t type is interface\n\treturn t == errorType //t type is struct\n}\n\nfunc formatName(name string) string {\n\tret := []rune(name)\n\tif len(ret) > 0 {\n\t\tret[0] = unicode.ToLower(ret[0])\n\t}\n\treturn string(ret)\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/common.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/language\"\n\t\"github.com/IBAX-io/go-ibax/packages/publisher\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\t\"github.com/IBAX-io/go-ibax/packages/template\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"gorm.io/gorm\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype commonApi struct {\n\tmode Mode\n}\n\nfunc newCommonApi(m Mode) *commonApi {\n\treturn &commonApi{\n\t\tmode: m,\n\t}\n}\n\ntype contractField struct {\n\tName     string `json:\"name\"`\n\tType     string `json:\"type\"`\n\tOptional bool   `json:\"optional\"`\n}\n\ntype GetContractResult struct {\n\tID         uint32          `json:\"id\"`\n\tStateID    uint32          `json:\"state\"`\n\tTableID    string          `json:\"tableid\"`\n\tWalletID   string          `json:\"walletid\"`\n\tTokenID    string          `json:\"tokenid\"`\n\tAddress    string          `json:\"address\"`\n\tFields     []contractField `json:\"fields\"`\n\tName       string          `json:\"name\"`\n\tAppId      uint32          `json:\"app_id\"`\n\tEcosystem  uint32          `json:\"ecosystem\"`\n\tConditions string          `json:\"conditions\"`\n}\n\nfunc getContract(r *http.Request, name string) *smart.Contract {\n\tvm := script.GetVM()\n\tif vm == nil {\n\t\treturn nil\n\t}\n\tclient := getClient(r)\n\tcontract := smart.VMGetContract(vm, name, uint32(client.EcosystemID))\n\tif contract == nil {\n\t\treturn nil\n\t}\n\treturn contract\n}\n\nfunc getContractInfo(contract *smart.Contract) *script.ContractInfo {\n\treturn contract.Info()\n}\n\nfunc (c *commonApi) GetContractInfo(ctx RequestContext, auth Auth, contractName string) (*GetContractResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tcontract := getContract(r, contractName)\n\tif contract == nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ContractError, \"contract_name\": contractName}).Debug(\"contract name\")\n\t\treturn nil, DefaultError(fmt.Sprintf(\"There is not %s contract\", contractName))\n\t}\n\n\tvar result GetContractResult\n\tinfo := getContractInfo(contract)\n\tcon := &sqldb.Contract{}\n\texits, err := con.Get(info.Owner.TableID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"contract_id\": info.Owner.TableID}).Error(\"get contract\")\n\t\treturn nil, DefaultError(fmt.Sprintf(\"get contract %d failed:%s\", info.Owner.TableID, err.Error()))\n\t}\n\tif !exits {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ContractError, \"contract id\": info.Owner.TableID}).Debug(\"get contract\")\n\t\treturn nil, DefaultError(fmt.Sprintf(\"There is not %d contract\", info.Owner.TableID))\n\t}\n\tfields := make([]contractField, 0)\n\tresult = GetContractResult{\n\t\tID:         uint32(info.Owner.TableID + consts.ShiftContractID),\n\t\tTableID:    converter.Int64ToStr(info.Owner.TableID),\n\t\tName:       info.Name,\n\t\tStateID:    info.Owner.StateID,\n\t\tWalletID:   converter.Int64ToStr(info.Owner.WalletID),\n\t\tTokenID:    converter.Int64ToStr(info.Owner.TokenID),\n\t\tAddress:    converter.AddressToString(info.Owner.WalletID),\n\t\tEcosystem:  uint32(con.EcosystemID),\n\t\tAppId:      uint32(con.AppID),\n\t\tConditions: con.Conditions,\n\t}\n\n\tif info.Tx != nil {\n\t\tfor _, fitem := range *info.Tx {\n\t\t\tfields = append(fields, contractField{\n\t\t\t\tName:     fitem.Name,\n\t\t\t\tType:     script.OriginalToString(fitem.Original),\n\t\t\t\tOptional: fitem.ContainsTag(script.TagOptional),\n\t\t\t})\n\t\t}\n\t}\n\tresult.Fields = fields\n\treturn &result, nil\n}\n\ntype ListResult struct {\n\tCount int64               `json:\"count\"`\n\tList  []map[string]string `json:\"list\"`\n}\n\nfunc (c *commonApi) GetContracts(ctx RequestContext, auth Auth, offset, limit *int) (*ListResult, *Error) {\n\tr := ctx.HTTPRequest()\n\n\tform := &paginatorForm{}\n\tif offset != nil {\n\t\tform.Offset = *offset\n\t}\n\tif limit != nil {\n\t\tform.Limit = *limit\n\t}\n\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tcontract := &sqldb.Contract{}\n\tcontract.EcosystemID = client.EcosystemID\n\n\tcount, err := contract.CountByEcosystem()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting table records count\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tcontracts, err := contract.GetListByEcosystem(form.Offset, form.Limit)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tlist := make([]map[string]string, len(contracts))\n\tfor i, c := range contracts {\n\t\tlist[i] = c.ToMap()\n\t\tlist[i][\"address\"] = converter.AddressToString(c.WalletID)\n\t}\n\n\tif len(list) == 0 {\n\t\tlist = nil\n\t}\n\n\treturn &ListResult{\n\t\tCount: count,\n\t\tList:  list,\n\t}, nil\n}\n\ntype roleInfo struct {\n\tID   string `json:\"id\"`\n\tName string `json:\"name\"`\n}\n\ntype notifyInfo struct {\n\tRoleID string `json:\"role_id\"`\n\tCount  int64  `json:\"count\"`\n}\n\ntype KeyInfoResult struct {\n\tAccount    string              `json:\"account\"`\n\tKeyId      string              `json:\"key_id\"`\n\tEcosystems []*keyEcosystemInfo `json:\"ecosystems\"`\n}\n\ntype keyEcosystemInfo struct {\n\tEcosystem     string       `json:\"ecosystem\"`\n\tName          string       `json:\"name\"`\n\tDigits        int64        `json:\"digits\"`\n\tRoles         []roleInfo   `json:\"roles,omitempty\"`\n\tNotifications []notifyInfo `json:\"notifications,omitempty\"`\n}\n\nfunc getNotifications(ecosystemID int64, key *sqldb.Key) ([]notifyInfo, error) {\n\tnotif, err := sqldb.GetNotificationsCount(ecosystemID, []string{key.AccountID})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlist := make([]notifyInfo, 0)\n\tfor _, n := range notif {\n\t\tif n.RecipientID != key.ID {\n\t\t\tcontinue\n\t\t}\n\n\t\tlist = append(list, notifyInfo{\n\t\t\tRoleID: converter.Int64ToStr(n.RoleID),\n\t\t\tCount:  n.Count,\n\t\t})\n\t}\n\treturn list, nil\n}\n\nfunc (c *commonApi) GetKeyInfo(ctx RequestContext, accountAddress string) (*KeyInfoResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tkeysList := make([]*keyEcosystemInfo, 0)\n\tkeyID := converter.StringToAddress(accountAddress)\n\tif keyID == 0 {\n\t\treturn nil, InvalidParamsError(fmt.Sprintf(\"account address %s is not valid\", accountAddress))\n\t}\n\n\tids, names, err := c.mode.EcosystemGetter.GetEcosystemLookup()\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tvar (\n\t\taccount = converter.AddressToString(keyID)\n\t\tfound   bool\n\t)\n\n\tfor i, ecosystemID := range ids {\n\t\tkey := &sqldb.Key{}\n\t\tkey.SetTablePrefix(ecosystemID)\n\t\tfound, err = key.Get(nil, keyID)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\t\teco := sqldb.Ecosystem{}\n\t\t_, err = eco.Get(nil, ecosystemID)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tkeyRes := &keyEcosystemInfo{\n\t\t\tEcosystem: converter.Int64ToStr(ecosystemID),\n\t\t\tName:      names[i],\n\t\t\tDigits:    eco.Digits,\n\t\t}\n\t\tra := &sqldb.RolesParticipants{}\n\t\troles, err := ra.SetTablePrefix(ecosystemID).GetActiveMemberRoles(key.AccountID)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tfor _, r := range roles {\n\t\t\tvar role roleInfo\n\t\t\tif err := json.Unmarshal([]byte(r.Role), &role); err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling role\")\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\t\t\tkeyRes.Roles = append(keyRes.Roles, role)\n\t\t}\n\t\tkeyRes.Notifications, err = getNotifications(ecosystemID, key)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting notifications\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\n\t\tkeysList = append(keysList, keyRes)\n\t}\n\n\t// in test mode, registration is open in the first ecosystem\n\tif len(keysList) == 0 {\n\t\tnotify := make([]notifyInfo, 0)\n\t\tnotify = append(notify, notifyInfo{})\n\t\tkeysList = append(keysList, &keyEcosystemInfo{\n\t\t\tEcosystem:     converter.Int64ToStr(ids[0]),\n\t\t\tName:          names[0],\n\t\t\tNotifications: notify,\n\t\t})\n\t}\n\n\treturn &KeyInfoResult{\n\t\tAccount:    account,\n\t\tKeyId:      strconv.FormatInt(keyID, 10),\n\t\tEcosystems: keysList,\n\t}, nil\n}\n\ntype ListForm struct {\n\tName string `json:\"name\"` //table name\n\tpaginatorForm\n\trowForm\n}\n\nfunc (f *ListForm) Validate(r *http.Request) error {\n\tif f == nil || f.Name == \"\" {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\tif err := f.paginatorForm.Validate(r); err != nil {\n\t\treturn err\n\t}\n\treturn f.rowForm.Validate(r)\n}\n\ntype rowForm struct {\n\tColumns string `json:\"columns\"`\n}\n\nfunc (f *rowForm) Validate(r *http.Request) error {\n\tif len(f.Columns) > 0 {\n\t\tcolumns := strings.Split(f.Columns, \",\")\n\t\tlist := make([]string, len(columns))\n\t\tfor k, column := range columns {\n\t\t\tlist[k] = converter.Sanitize(column, `->`)\n\t\t}\n\t\tf.Columns = strings.Join(list, \",\")\n\t}\n\treturn nil\n}\n\nfunc checkAccess(tableName, columns string, client *UserClient) (table string, cols string, err error) {\n\tsc := smart.SmartContract{\n\t\tCLB: conf.Config.IsSupportingCLB(),\n\t\tVM:  script.GetVM(),\n\t\tTxSmart: &types.SmartTransaction{\n\t\t\tHeader: &types.Header{\n\t\t\t\tEcosystemID: client.EcosystemID,\n\t\t\t\tKeyID:       client.KeyID,\n\t\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t\t},\n\t\t},\n\t}\n\ttable, _, cols, err = sc.CheckAccess(tableName, columns, client.EcosystemID)\n\treturn\n}\n\nfunc (c *commonApi) GetList(ctx RequestContext, auth Auth, form *ListWhereForm) (*ListResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tif form == nil {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tvar (\n\t\terr                 error\n\t\ttable, where, order string\n\t)\n\ttable, form.Columns, err = checkAccess(form.Name, form.Columns, client)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\torder, err = qb.GetOrder(table, form.Order, true)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tvar q *gorm.DB\n\tq = sqldb.GetTableListQuery(form.Name, client.EcosystemID)\n\n\tif len(form.Columns) > 0 {\n\t\tq = q.Select(\"id,\" + form.Columns)\n\t}\n\n\tif form.Where != nil {\n\t\tvar inWhere any\n\t\tswitch form.Where.(type) {\n\t\tcase string:\n\t\t\tif len(form.Where.(string)) > 0 {\n\t\t\t\tinWhere, _, err = template.ParseObject([]rune(form.Where.(string)))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, DefaultError(\"where parse object failed\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tinWhere = \"\"\n\t\t\t}\n\t\t}\n\n\t\tswitch v := inWhere.(type) {\n\t\tcase string:\n\t\t\tif len(v) == 0 {\n\t\t\t\twhere = `true`\n\t\t\t} else {\n\t\t\t\treturn nil, DefaultError(\"Where has wrong format\")\n\t\t\t}\n\t\tcase map[string]any:\n\t\t\twhere, err = qb.GetWhere(types.LoadMap(v))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\t\tcase *types.Map:\n\t\t\twhere, err = qb.GetWhere(v)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, DefaultError(\"Where has wrong format\")\n\t\t}\n\t\tq = q.Where(where)\n\t}\n\n\tresult := new(ListResult)\n\terr = q.Count(&result.Count).Error\n\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).\n\t\t\tErrorf(\"selecting rows from table %s select %s where %s\", table, smart.PrepareColumns([]string{form.Columns}), where)\n\t\treturn nil, DefaultError(fmt.Sprintf(\"Table %s has not been found\", table))\n\t}\n\n\tif len(order) > 0 {\n\t\trows, err := q.Order(order).Offset(form.Offset).Limit(form.Limit).Rows()\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tresult.List, err = sqldb.GetResult(rows)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t} else {\n\t\trows, err := q.Order(\"id ASC\").Offset(form.Offset).Limit(form.Limit).Rows()\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tresult.List, err = sqldb.GetResult(rows)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\ntype HonorNodeJSON struct {\n\tTCPAddress string `json:\"tcp_address\"`\n\tAPIAddress string `json:\"api_address\"`\n\tPublicKey  string `json:\"public_key\"`\n\tUnbanTime  string `json:\"unban_time\"`\n\tStopped    bool   `json:\"stopped\"`\n}\n\ntype NetworkResult struct {\n\tNetworkID     string          `json:\"network_id\"`\n\tCentrifugoURL string          `json:\"centrifugo_url\"`\n\tTest          bool            `json:\"test\"`\n\tPrivate       bool            `json:\"private\"`\n\tHonorNodes    []HonorNodeJSON `json:\"honor_nodes\"`\n}\n\nfunc getNodesJSON() []HonorNodeJSON {\n\tnodes := make([]HonorNodeJSON, 0)\n\tfor _, node := range syspar.GetNodes() {\n\t\tnodes = append(nodes, HonorNodeJSON{\n\t\t\tTCPAddress: node.TCPAddress,\n\t\t\tAPIAddress: node.APIAddress,\n\t\t\tPublicKey:  crypto.PubToHex(node.PublicKey),\n\t\t\tUnbanTime:  strconv.FormatInt(node.UnbanTime.Unix(), 10),\n\t\t})\n\t}\n\treturn nodes\n}\n\nconst defaultSectionsLimit = 100\n\ntype SectionsForm struct {\n\tpaginatorForm\n\tLang string `schema:\"lang\"`\n}\n\nfunc (f *SectionsForm) Validate(r *http.Request) error {\n\tif f == nil {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\tif err := f.paginatorForm.Validate(r); err != nil {\n\t\treturn err\n\t}\n\n\tif len(f.Lang) == 0 {\n\t\tf.Lang = r.Header.Get(\"Accept-Language\")\n\t}\n\n\treturn nil\n}\n\nfunc (c *commonApi) GetSections(ctx RequestContext, auth Auth, params *SectionsForm) (*ListResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tform := &SectionsForm{}\n\tif params != nil {\n\t\tform = params\n\t}\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\ttable := \"1_sections\"\n\tq := sqldb.GetDB(nil).Table(table).Where(\"ecosystem = ? AND status > 0\", client.EcosystemID).Order(\"id ASC\")\n\n\tresult := new(ListResult)\n\terr := q.Count(&result.Count).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting table records count\")\n\t\treturn nil, DefaultError(fmt.Sprintf(\"Table %s has not been found\", table))\n\t}\n\n\trows, err := q.Offset(form.Offset).Limit(form.Limit).Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tresult.List, err = sqldb.GetResult(rows)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tvar sections []map[string]string\n\tfor _, item := range result.List {\n\t\tvar roles []int64\n\t\tif err := json.Unmarshal([]byte(item[\"roles_access\"]), &roles); err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tif len(roles) > 0 {\n\t\t\tvar added bool\n\t\t\tfor _, v := range roles {\n\t\t\t\tif v == client.RoleID {\n\t\t\t\t\tadded = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !added {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif item[\"status\"] == consts.StatusMainPage {\n\t\t\troles := &sqldb.Role{}\n\t\t\troles.SetTablePrefix(1)\n\t\t\trole, err := roles.Get(nil, client.RoleID)\n\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Debug(\"Getting role by id\")\n\t\t\t\treturn nil, DefaultError(err.Error())\n\t\t\t}\n\t\t\tif role == true && roles.DefaultPage != \"\" {\n\t\t\t\titem[\"default_page\"] = roles.DefaultPage\n\t\t\t}\n\t\t}\n\n\t\titem[\"title\"] = language.LangMacro(item[\"title\"], int(client.EcosystemID), form.Lang)\n\t\tsections = append(sections, item)\n\t}\n\tresult.List = sections\n\treturn result, nil\n}\n\ntype RowResult struct {\n\tValue map[string]string `json:\"value\"`\n}\n\n// GetRow\n// whereColumn: find whereColumn = id or Find id\n// columns: select colunms\n// example: \"params\":[\"@1history\",6660819716178795186,\"sender_id\",\"created_at,ecosystem\"]\nfunc (c *commonApi) GetRow(ctx RequestContext, auth Auth, tableName string, id int64, columns *string, whereColumn *string) (*RowResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tform := &rowForm{}\n\tif columns != nil {\n\t\tform.Columns = *columns\n\t\tif err := parameterValidator(r, form); err != nil {\n\t\t\treturn nil, InvalidParamsError(err.Error())\n\t\t}\n\t}\n\tidStr := strconv.FormatInt(id, 10)\n\tif tableName == \"\" || idStr == \"\" {\n\t\treturn nil, InvalidParamsError(\"tableName or id invalid\")\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tq := sqldb.GetDB(nil).Limit(1)\n\n\tvar (\n\t\terr   error\n\t\ttable string\n\t)\n\ttable, form.Columns, err = checkAccess(tableName, form.Columns, client)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tcol := `id`\n\tif whereColumn != nil && len(*whereColumn) > 0 {\n\t\tcol = converter.Sanitize(*whereColumn, `-`)\n\t}\n\tif converter.FirstEcosystemTables[tableName] {\n\t\tq = q.Table(table).Where(col+\" = ? and ecosystem = ?\", idStr, client.EcosystemID)\n\t} else {\n\t\tq = q.Table(table).Where(col+\" = ?\", idStr)\n\t}\n\n\tif len(form.Columns) > 0 {\n\t\tq = q.Select(form.Columns)\n\t}\n\n\trows, err := q.Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\treturn nil, DefaultError(\"DB query is wrong\")\n\t}\n\n\tresult, err := sqldb.GetResult(rows)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tif len(result) == 0 {\n\t\treturn nil, NotFoundError()\n\t}\n\n\treturn &RowResult{\n\t\tValue: result[0],\n\t}, nil\n}\n\ntype PartModel interface {\n\tSetTablePrefix(prefix string)\n\tGet(name string) (bool, error)\n}\n\nfunc getPageRowMux(ctx RequestContext, name string) (PartModel, *Error) {\n\treturn getInterfaceRow(ctx, name, &sqldb.Page{})\n}\n\nfunc getMenuRowMux(ctx RequestContext, name string) (PartModel, *Error) {\n\treturn getInterfaceRow(ctx, name, &sqldb.Menu{})\n}\n\nfunc getSnippetRowMux(ctx RequestContext, name string) (PartModel, *Error) {\n\treturn getInterfaceRow(ctx, name, &sqldb.Snippet{})\n}\n\nfunc getInterfaceRow(ctx RequestContext, name string, c PartModel) (PartModel, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\n\tc.SetTablePrefix(client.Prefix())\n\tif ok, err := c.Get(name); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting one row\")\n\t\treturn nil, DefaultError(\"DB query is wrong\")\n\t} else if !ok {\n\t\treturn nil, NotFoundError()\n\t}\n\treturn c, nil\n}\n\nfunc (c *commonApi) GetPageRow(ctx RequestContext, auth Auth, name string) (PartModel, *Error) {\n\tif name == \"\" {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\treturn getPageRowMux(ctx, name)\n}\n\nfunc (c *commonApi) GetMenuRow(ctx RequestContext, auth Auth, name string) (PartModel, *Error) {\n\tif name == \"\" {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\treturn getMenuRowMux(ctx, name)\n}\n\nfunc (c *commonApi) GetSnippetRow(ctx RequestContext, auth Auth, name string) (PartModel, *Error) {\n\tif name == \"\" {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\treturn getSnippetRowMux(ctx, name)\n}\n\ntype columnInfo struct {\n\tName string `json:\"name\"`\n\tType string `json:\"type\"`\n\tPerm string `json:\"perm\"`\n}\n\ntype TableResult struct {\n\tName       string       `json:\"name\"`\n\tInsert     string       `json:\"insert\"`\n\tNewColumn  string       `json:\"new_column\"`\n\tUpdate     string       `json:\"update\"`\n\tRead       string       `json:\"read,omitempty\"`\n\tFilter     string       `json:\"filter,omitempty\"`\n\tConditions string       `json:\"conditions\"`\n\tAppID      string       `json:\"app_id\"`\n\tColumns    []columnInfo `json:\"columns\"`\n}\n\nfunc (c *commonApi) GetTable(ctx RequestContext, auth Auth, name string) (*TableResult, *Error) {\n\tif name == \"\" {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\tprefix := client.Prefix()\n\n\ttable := &sqldb.Table{}\n\ttable.SetTablePrefix(prefix)\n\n\t_, err := table.Get(nil, strings.ToLower(name))\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"Getting table\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tif len(table.Name) == 0 {\n\t\treturn nil, DefaultError(fmt.Sprintf(\"Table %s has not been found\", name))\n\t}\n\n\tvar columnsMap map[string]string\n\terr = json.Unmarshal([]byte(table.Columns), &columnsMap)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"Unmarshalling table columns to json\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tcolumns := make([]columnInfo, 0)\n\tfor key, value := range columnsMap {\n\t\tcolType, err := sqldb.NewDbTransaction(nil).GetColumnType(prefix+`_`+name, key)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting column type from db\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tcolumns = append(columns, columnInfo{\n\t\t\tName: key,\n\t\t\tPerm: value,\n\t\t\tType: colType,\n\t\t})\n\t}\n\treturn &TableResult{\n\t\tName:       table.Name,\n\t\tInsert:     table.Permissions.Insert,\n\t\tNewColumn:  table.Permissions.NewColumn,\n\t\tUpdate:     table.Permissions.Update,\n\t\tRead:       table.Permissions.Read,\n\t\tFilter:     table.Permissions.Filter,\n\t\tConditions: table.Conditions,\n\t\tAppID:      converter.Int64ToStr(table.AppID),\n\t\tColumns:    columns,\n\t}, nil\n}\n\ntype tableInfo struct {\n\tName  string `json:\"name\"`\n\tCount string `json:\"count\"`\n}\n\ntype TableCountResult struct {\n\tCount int64       `json:\"count\"`\n\tList  []tableInfo `json:\"list\"`\n}\n\nfunc (c *commonApi) GetTableCount(ctx RequestContext, auth Auth, offset, limit *int) (*TableCountResult, *Error) {\n\tr := ctx.HTTPRequest()\n\n\tform := &paginatorForm{}\n\tif offset != nil {\n\t\tform.Offset = *offset\n\t}\n\tif limit != nil {\n\t\tform.Limit = *limit\n\t}\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\tprefix := client.Prefix()\n\n\ttable := &sqldb.Table{}\n\ttable.SetTablePrefix(prefix)\n\n\tcount, err := table.Count()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting records count from tables\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\trows, err := sqldb.GetDB(nil).Table(table.TableName()).Where(\"ecosystem = ?\", client.EcosystemID).Offset(form.Offset).Limit(form.Limit).Rows()\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"Getting rows from table\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tlist, err := sqldb.GetResult(rows)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting names from tables\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tresult := &TableCountResult{\n\t\tCount: count,\n\t\tList:  make([]tableInfo, len(list)),\n\t}\n\tfor i, item := range list {\n\t\terr = sqldb.GetTableQuery(item[\"name\"], client.EcosystemID).Count(&count).Error\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting count from table\")\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\n\t\tresult.List[i].Name = item[\"name\"]\n\t\tresult.List[i].Count = converter.Int64ToStr(count)\n\t}\n\treturn result, nil\n}\n\nfunc (c *commonApi) GetVersion() string {\n\treturn consts.Version() + \" \" + node.NodePauseType().String()\n}\n\nfunc replaceHttpSchemeToWs(centrifugoURL string) string {\n\tif strings.HasPrefix(centrifugoURL, \"http:\") {\n\t\treturn strings.Replace(centrifugoURL, \"http:\", \"ws:\", -1)\n\t} else if strings.HasPrefix(centrifugoURL, \"https:\") {\n\t\treturn strings.Replace(centrifugoURL, \"https:\", \"wss:\", -1)\n\t}\n\treturn centrifugoURL\n}\n\nfunc centrifugoAddressHandler(r *http.Request) (string, error) {\n\tlogger := getLogger(r)\n\n\tif _, err := publisher.GetStats(); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.CentrifugoError, \"error\": err}).Warn(\"on getting centrifugo stats\")\n\t\treturn \"\", err\n\t}\n\n\treturn replaceHttpSchemeToWs(conf.Config.Centrifugo.URL), nil\n}\n\nfunc (c *commonApi) GetConfig(ctx RequestContext, option string) (map[string]any, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\tif option == \"\" {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject, \"error\": \"option not specified\"}).Error(\"on getting option in config handler\")\n\t\treturn nil, NotFoundError()\n\t}\n\n\trets := make(map[string]any)\n\tvar err error\n\tswitch option {\n\tcase \"centrifugo\":\n\t\trets[option], err = centrifugoAddressHandler(r)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\treturn rets, nil\n\t}\n\n\treturn nil, NotFoundError()\n}\n\nfunc parseEcosystem(in string) (string, string) {\n\tecosystem, name := converter.ParseName(in)\n\tif ecosystem == 0 {\n\t\treturn ``, name\n\t}\n\treturn converter.Int64ToStr(ecosystem), name\n}\n\nfunc pageValue(r *http.Request, name string) (*sqldb.Page, string, error) {\n\tlogger := getLogger(r)\n\tclient := getClient(r)\n\n\tvar ecosystem string\n\tpage := &sqldb.Page{}\n\tif strings.HasPrefix(name, `@`) {\n\t\tecosystem, name = parseEcosystem(name)\n\t\tif len(name) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\n\t\t\t\t\"type\":  consts.NotFound,\n\t\t\t\t\"value\": name,\n\t\t\t}).Debug(\"page not found\")\n\t\t\treturn nil, ``, errors.New(consts.NotFound)\n\t\t}\n\t} else {\n\t\tecosystem = client.Prefix()\n\t}\n\tpage.SetTablePrefix(ecosystem)\n\tfound, err := page.Get(name)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting page\")\n\t\treturn nil, ``, err\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"page not found\")\n\t\treturn nil, ``, errors.New(consts.NotFound)\n\t}\n\treturn page, ecosystem, nil\n}\n\nfunc (c *commonApi) GetPageValidatorsCount(ctx RequestContext, name string) (*map[string]int64, *Error) {\n\tr := ctx.HTTPRequest()\n\tif name == \"\" {\n\t\treturn nil, NotFoundError()\n\t}\n\tpage, _, err := pageValue(r, name)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tres := map[string]int64{\"validate_count\": page.ValidateCount}\n\treturn &res, nil\n}\n\nfunc initVars(r *http.Request, vals *map[string]string) *map[string]string {\n\tclient := getClient(r)\n\n\tvars := make(map[string]string)\n\tif vals != nil {\n\t\tfor k, v := range *vals {\n\t\t\tvars[k] = v\n\t\t}\n\t}\n\tvars[\"_full\"] = \"0\"\n\tvars[\"current_time\"] = fmt.Sprintf(\"%d\", time.Now().Unix())\n\tvars[\"guest_key\"] = consts.GuestKey\n\tvars[\"guest_account\"] = consts.GuestAddress\n\tvars[\"black_hole_key\"] = strconv.FormatInt(converter.HoleAddrMap[converter.BlackHoleAddr].K, 10)\n\tvars[\"black_hole_account\"] = converter.HoleAddrMap[converter.BlackHoleAddr].S\n\tvars[\"white_hole_key\"] = strconv.FormatInt(converter.HoleAddrMap[converter.WhiteHoleAddr].K, 10)\n\tvars[\"white_hole_account\"] = converter.HoleAddrMap[converter.WhiteHoleAddr].S\n\tif client.KeyID != 0 {\n\t\tvars[\"ecosystem_id\"] = converter.Int64ToStr(client.EcosystemID)\n\t\tvars[\"key_id\"] = converter.Int64ToStr(client.KeyID)\n\t\tvars[\"account_id\"] = client.AccountID\n\t\tvars[\"role_id\"] = converter.Int64ToStr(client.RoleID)\n\t\tvars[\"ecosystem_name\"] = client.EcosystemName\n\t} else {\n\t\tvars[\"ecosystem_id\"] = vars[\"ecosystem\"]\n\t\tdelete(vars, \"ecosystem\")\n\t\tif len(vars[\"keyID\"]) > 0 {\n\t\t\tvars[\"key_id\"] = vars[\"keyID\"]\n\t\t\tvars[\"account_id\"] = converter.AddressToString(converter.StrToInt64(vars[\"keyID\"]))\n\t\t} else {\n\t\t\tvars[\"key_id\"] = \"0\"\n\t\t\tvars[\"account_id\"] = \"\"\n\t\t}\n\t\tif len(vars[\"roleID\"]) > 0 {\n\t\t\tvars[\"role_id\"] = vars[\"roleID\"]\n\t\t} else {\n\t\t\tvars[\"role_id\"] = \"0\"\n\t\t}\n\t\tif len(vars[\"ecosystem_id\"]) != 0 {\n\t\t\tecosystems := sqldb.Ecosystem{}\n\t\t\tif found, _ := ecosystems.Get(nil, converter.StrToInt64(vars[\"ecosystem_id\"])); found {\n\t\t\t\tvars[\"ecosystem_name\"] = ecosystems.Name\n\t\t\t}\n\t\t}\n\t}\n\tif _, ok := vars[\"lang\"]; !ok {\n\t\tvars[\"lang\"] = r.Header.Get(\"Accept-Language\")\n\t}\n\n\treturn &vars\n}\n\ntype ContentResult struct {\n\tMenu       string          `json:\"menu,omitempty\"`\n\tMenuTree   json.RawMessage `json:\"menutree,omitempty\"`\n\tTitle      string          `json:\"title,omitempty\"`\n\tTree       json.RawMessage `json:\"tree\"`\n\tNodesCount int64           `json:\"nodesCount,omitempty\"`\n}\n\nconst strOne = `1`\n\nfunc (c *commonApi) GetSource(ctx RequestContext, auth Auth, name string, vals *map[string]string) (*ContentResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tif name == \"\" {\n\t\treturn nil, NotFoundError()\n\t}\n\tpage, _, err := pageValue(r, name)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tvar timeout bool\n\tvars := initVars(r, vals)\n\t(*vars)[\"_full\"] = strOne\n\tret := template.Template2JSON(page.Value, &timeout, vars)\n\n\treturn &ContentResult{Tree: ret}, nil\n}\n\nfunc getPage(r *http.Request, name string, vals *map[string]string) (result *ContentResult, err error) {\n\tpage, _, err := pageValue(r, name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogger := getLogger(r)\n\n\tclient := getClient(r)\n\tmenu := &sqldb.Menu{}\n\tmenu.SetTablePrefix(client.Prefix())\n\t_, err = menu.Get(page.Menu)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting page menu\")\n\t\treturn nil, errors.New(\"Server error\")\n\t}\n\tvar wg sync.WaitGroup\n\tvar timeout bool\n\twg.Add(2)\n\tsuccess := make(chan bool, 1)\n\tgo func() {\n\t\tdefer wg.Done()\n\n\t\tvars := initVars(r, vals)\n\t\t(*vars)[\"app_id\"] = converter.Int64ToStr(page.AppID)\n\n\t\tret := template.Template2JSON(page.Value, &timeout, vars)\n\t\tif timeout {\n\t\t\treturn\n\t\t}\n\t\tretmenu := template.Template2JSON(menu.Value, &timeout, vars)\n\t\tif timeout {\n\t\t\treturn\n\t\t}\n\t\tresult = &ContentResult{\n\t\t\tTree:       ret,\n\t\t\tMenu:       page.Menu,\n\t\t\tMenuTree:   retmenu,\n\t\t\tNodesCount: page.ValidateCount,\n\t\t}\n\t\tsuccess <- true\n\t}()\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tif conf.Config.LocalConf.MaxPageGenerationTime == 0 {\n\t\t\treturn\n\t\t}\n\t\tselect {\n\t\tcase <-time.After(time.Duration(conf.Config.LocalConf.MaxPageGenerationTime) * time.Millisecond):\n\t\t\ttimeout = true\n\t\tcase <-success:\n\t\t}\n\t}()\n\twg.Wait()\n\tclose(success)\n\n\tif timeout {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.InvalidObject}).Error(page.Name + \" is a heavy page\")\n\t\treturn nil, errors.New(\"this page is heavy\")\n\t}\n\n\treturn result, nil\n}\n\nfunc (c *commonApi) GetPage(ctx RequestContext, auth Auth, name string, vals *map[string]string) (*ContentResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tresult, err := getPage(r, name, vals)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\treturn result, nil\n}\n\ntype hashResult struct {\n\tHash string `json:\"hash\"`\n}\n\nfunc (c *commonApi) GetPageHash(ctx RequestContext, name string, ecosystem *int64, vals *map[string]string) (*hashResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tlogger := getLogger(r)\n\n\tif ecosystem != nil && !strings.HasPrefix(name, \"@\") && *ecosystem != 0 {\n\t\tname = \"@\" + strconv.FormatInt(*ecosystem, 10) + name\n\t}\n\tresult, err := getPage(r, name, vals)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\tout, err := json.Marshal(result)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"getting string for hash\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\n\treturn &hashResult{Hash: hex.EncodeToString(crypto.Hash(out))}, nil\n}\n\nfunc (c *commonApi) GetMenu(ctx RequestContext, auth Auth, name string, vals *map[string]string) (*ContentResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tvar ecosystem string\n\tmenu := &sqldb.Menu{}\n\tif strings.HasPrefix(name, `@`) {\n\t\tecosystem, name = parseEcosystem(name)\n\t\tif len(name) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\n\t\t\t\t\"type\":  consts.NotFound,\n\t\t\t\t\"value\": name,\n\t\t\t}).Debug(\"page not found\")\n\t\t\treturn nil, NotFoundError()\n\t\t}\n\t} else {\n\t\tecosystem = client.Prefix()\n\t}\n\n\tmenu.SetTablePrefix(ecosystem)\n\tfound, err := menu.Get(name)\n\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting menu\")\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound}).Debug(\"menu not found\")\n\t\treturn nil, NotFoundError()\n\t}\n\tvar timeout bool\n\tret := template.Template2JSON(menu.Value, &timeout, initVars(r, vals))\n\n\treturn &ContentResult{Tree: ret, Title: menu.Title}, nil\n}\n\ntype jsonContentForm struct {\n\tTemplate string `json:\"template\"`\n\tSource   bool   `json:\"source\"`\n}\n\nfunc (f *jsonContentForm) Validate(r *http.Request) error {\n\tif f == nil || len(f.Template) == 0 {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\treturn nil\n}\n\nfunc (c *commonApi) GetContent(ctx RequestContext, form *jsonContentForm, vals *map[string]string) (*ContentResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tif err := parameterValidator(r, form); err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\tvar timeout bool\n\tvars := initVars(r, vals)\n\n\tif form.Source {\n\t\t(*vars)[\"_full\"] = strOne\n\t}\n\n\tret := template.Template2JSON(form.Template, &timeout, vars)\n\n\treturn &ContentResult{Tree: ret}, nil\n}\n\nfunc (c *commonApi) GetTxCount(ctx RequestContext) (*int64, *Error) {\n\tr := ctx.HTTPRequest()\n\tcount, err := sqldb.GetTxCount()\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on getting tx count\")\n\t\treturn nil, InternalError(err.Error())\n\t}\n\n\treturn &count, nil\n}\n\nfunc (c *commonApi) GetEcosystemCount(ctx RequestContext) (*int64, *Error) {\n\tr := ctx.HTTPRequest()\n\ttotal, err := sqldb.GetAllSystemCount()\n\tif err != nil {\n\t\tlogger := getLogger(r)\n\t\tlogger.WithError(err).Error(\"on getting ecosystem count\")\n\t\treturn nil, InternalError(err.Error())\n\t}\n\n\treturn &total, nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/common_forms.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nconst (\n\tdefaultPaginatorLimit = 25\n\tmaxPaginatorLimit     = 100\n)\n\ntype paginatorForm struct {\n\tdefaultLimit int\n\n\tLimit  int `json:\"limit\"`\n\tOffset int `json:\"offset\"`\n}\n\nfunc (f *paginatorForm) Validate(r *http.Request) error {\n\tif f == nil {\n\t\treturn errors.New(paramsEmpty)\n\t}\n\tf.defaultLimit = defaultPaginatorLimit\n\tif f.Limit <= 0 {\n\t\tf.Limit = f.defaultLimit\n\t}\n\n\tif f.Limit > maxPaginatorLimit {\n\t\tf.Limit = maxPaginatorLimit\n\t}\n\n\treturn nil\n}\n\ntype paramsForm struct {\n\tnopeValidator\n\tNames []string `schema:\"names\"`\n}\n\ntype nopeValidator struct{}\n\nfunc (np nopeValidator) Validate(r *http.Request) error {\n\treturn nil\n}\n\nfunc (f *paramsForm) AcceptNames(names string) {\n\tif names != \"\" {\n\t\tf.Names = strings.Split(names, \",\")\n\t}\n}\n\ntype ecosystemForm struct {\n\tEcosystemID     int64  `json:\"ecosystem\"`\n\tEcosystemPrefix string `schema:\"-\"`\n\tValidator       types.EcosystemGetter\n}\n\nfunc (f *ecosystemForm) Validate(r *http.Request) error {\n\tif f.Validator == nil {\n\t\tpanic(\"ecosystemForm.Validator should not be empty\")\n\t}\n\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\n\tecosysID, err := f.Validator.ValidateId(f.EcosystemID, client.EcosystemID, logger)\n\tif err != nil {\n\t\tif err.Error() == \"Ecosystem not found\" {\n\t\t\terr = fmt.Errorf(\"ecosystem %d doesn't exist\", f.EcosystemID)\n\t\t}\n\t\treturn err\n\t}\n\n\tf.EcosystemID = ecosysID\n\tf.EcosystemPrefix = converter.Int64ToStr(f.EcosystemID)\n\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/context.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"github.com/golang-jwt/jwt/v4\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype contextKey int\n\nconst (\n\tcontextKeyLogger contextKey = iota\n\tcontextKeyToken\n\tcontextKeyClient\n)\n\nfunc setContext(r *http.Request, key, value any) *http.Request {\n\treturn r.WithContext(context.WithValue(r.Context(), key, value))\n}\n\nfunc getContext(r *http.Request, key any) any {\n\treturn r.Context().Value(key)\n}\n\nfunc setLogger(r *http.Request, log *log.Entry) *http.Request {\n\treturn setContext(r, contextKeyLogger, log)\n}\n\nfunc getLogger(r *http.Request) *log.Entry {\n\tif v := getContext(r, contextKeyLogger); v != nil {\n\t\treturn v.(*log.Entry)\n\t}\n\treturn nil\n}\n\nfunc setToken(r *http.Request, token *jwt.Token) *http.Request {\n\treturn setContext(r, contextKeyToken, token)\n}\n\nfunc getToken(r *http.Request) *jwt.Token {\n\tif v := getContext(r, contextKeyToken); v != nil {\n\t\treturn v.(*jwt.Token)\n\t}\n\treturn nil\n}\n\nfunc setClient(r *http.Request, client *UserClient) *http.Request {\n\treturn setContext(r, contextKeyClient, client)\n}\n\nfunc getClient(r *http.Request) *UserClient {\n\tif v := getContext(r, contextKeyClient); v != nil {\n\t\treturn v.(*UserClient)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/data.go",
    "content": "package jsonrpc\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype NotSingle struct {\n}\n\ntype dataApi struct {\n}\n\nfunc newDataApi() *dataApi {\n\treturn &dataApi{}\n}\n\nfunc compareHash(data []byte, urlHash string) bool {\n\turlHash = strings.ToLower(urlHash)\n\n\tvar hash []byte\n\tswitch len(urlHash) {\n\tcase 32:\n\t\th := md5.Sum(data)\n\t\thash = h[:]\n\tcase 64:\n\t\thash = crypto.Hash(data)\n\t}\n\n\treturn hex.EncodeToString(hash) == urlHash\n}\n\nfunc (d *dataApi) BinaryVerify(ctx RequestContext, notSingle NotSingle, binaryId int64, hash string) *Error {\n\tif binaryId <= 0 {\n\t\treturn DefaultError(fmt.Sprintf(invalidParams, \"binary Id\"))\n\t}\n\tif hash == \"\" {\n\t\treturn DefaultError(fmt.Sprintf(invalidParams, \"hash\"))\n\t}\n\tr := ctx.HTTPRequest()\n\tw := ctx.HTTPResponseWriter()\n\n\tlogger := getLogger(r)\n\n\tbin := sqldb.Binary{}\n\tfound, err := bin.GetByID(binaryId)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Errorf(\"getting binary by id\")\n\t\treturn DefaultError(err.Error())\n\t}\n\n\tif !found {\n\t\treturn NotFoundError()\n\t}\n\n\tif !compareHash(bin.Data, hash) {\n\t\treturn DefaultError(\"Hash is incorrect\")\n\t}\n\n\tw.Header().Set(\"Content-Type\", bin.MimeType)\n\tw.Header().Set(\"Content-Disposition\", fmt.Sprintf(`attachment; filename=\"%s\"`, bin.Name))\n\tw.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\n\tw.Write(bin.Data)\n\treturn nil\n}\n\nfunc (d *dataApi) DataVerify(ctx RequestContext, notSingle NotSingle, table, column string, id int64, hash string) *Error {\n\tif table == \"\" || column == \"\" || id <= 0 || hash == \"\" {\n\t\treturn InvalidParamsError(\"tableName or column or id or hash invalid\")\n\t}\n\tr := ctx.HTTPRequest()\n\tw := ctx.HTTPResponseWriter()\n\tlogger := getLogger(r)\n\n\tdata, err := sqldb.GetColumnByID(table, column, id)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"selecting data from table\")\n\t\treturn NotFoundError()\n\t}\n\n\tif !compareHash([]byte(data), hash) {\n\t\treturn DefaultError(\"Hash is incorrect\")\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"application/octet-stream\")\n\tw.Header().Set(\"Content-Disposition\", \"attachment\")\n\tw.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\n\tw.Write([]byte(data))\n\treturn nil\n}\n\nfunc (d *dataApi) GetAvatar(ctx RequestContext, notSingle NotSingle, account string, ecosystemId int64) *Error {\n\tif account == \"\" || ecosystemId <= 0 {\n\t\treturn InvalidParamsError(\"account or ecosystemId invalid\")\n\t}\n\tr := ctx.HTTPRequest()\n\tw := ctx.HTTPResponseWriter()\n\tlogger := getLogger(r)\n\n\tmember := &sqldb.Member{}\n\tmember.SetTablePrefix(converter.Int64ToStr(ecosystemId))\n\n\tfound, err := member.Get(account)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\n\t\t\t\"type\":      consts.DBError,\n\t\t\t\"error\":     err,\n\t\t\t\"ecosystem\": ecosystemId,\n\t\t\t\"account\":   account,\n\t\t}).Error(\"getting member\")\n\t\treturn DefaultError(err.Error())\n\t}\n\n\tif !found {\n\t\treturn NotFoundError()\n\t}\n\n\tif member.ImageID == nil {\n\t\treturn NotFoundError()\n\t}\n\n\tbin := &sqldb.Binary{}\n\tbin.SetTablePrefix(converter.Int64ToStr(ecosystemId))\n\tfound, err = bin.GetByID(*member.ImageID)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"image_id\": *member.ImageID}).Errorf(\"on getting binary by id\")\n\n\t\treturn DefaultError(err.Error())\n\t}\n\n\tif !found {\n\t\treturn NotFoundError()\n\t}\n\n\tif len(bin.Data) == 0 {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject, \"error\": err, \"image_id\": *member.ImageID}).Errorf(\"on check avatar size\")\n\t\treturn NotFoundError()\n\t}\n\n\tw.Header().Set(\"Content-Type\", bin.MimeType)\n\tw.Header().Set(\"Content-Length\", strconv.Itoa(len(bin.Data)))\n\tif _, err := w.Write(bin.Data); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"unable to write image\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/debug.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"runtime\"\n)\n\ntype debugApi struct {\n}\n\nfunc newDebugApi() *debugApi {\n\treturn &debugApi{}\n}\n\ntype memMetric struct {\n\tAlloc uint64 `json:\"alloc\"`\n\tSys   uint64 `json:\"sys\"`\n}\n\nfunc (c *debugApi) GetMemStat() (*memMetric, *Error) {\n\tvar m runtime.MemStats\n\truntime.ReadMemStats(&m)\n\n\t//Alloc: Number of bytes allocated and still in use\n\t//Sys: The number of bytes fetched from the system (total)\n\treturn &memMetric{Alloc: m.Alloc, Sys: m.Sys}, nil\n}\n\ntype banMetric struct {\n\tNodePosition int  `json:\"node_position\"`\n\tStatus       bool `json:\"status\"`\n}\n\nfunc (c *debugApi) GetNodeBanStat() (*[]banMetric, *Error) {\n\tnodes := syspar.GetNodes()\n\tlist := make([]banMetric, 0, len(nodes))\n\n\tb := node.GetNodesBanService()\n\tfor i, n := range nodes {\n\t\tlist = append(list, banMetric{\n\t\t\tNodePosition: i,\n\t\t\tStatus:       b.IsBanned(n),\n\t\t})\n\t}\n\n\treturn &list, nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/ecosystem_params.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\ntype ParamResult struct {\n\tID         string `json:\"id\"`\n\tName       string `json:\"name\"`\n\tValue      string `json:\"value\"`\n\tConditions string `json:\"conditions\"`\n}\n\ntype ParamsResult struct {\n\tList []ParamResult `json:\"list\"`\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/errors.go",
    "content": "package jsonrpc\n\nimport (\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n)\n\ntype ErrorCode int\n\ntype Error struct {\n\tCode    ErrorCode      `json:\"code\"`\n\tMessage string         `json:\"message\"`\n\tData    map[string]any `json:\"data,omitempty\"`\n}\n\nconst (\n\tErrCodeDefault             = -32000\n\tErrCodeInvalidInput        = -32001\n\tErrCodeResourceNotFound    = -32002\n\tErrCodeResourceUnavailable = -32003\n\tErrCodeTransactionRejected = -32004\n\tErrCodeMethodNotSupported  = -32005\n\tErrCodeLimitExceeded       = -32006\n\tErrCodeParseError          = -32007\n\tErrCodeInvalidRequest      = -32008\n\tErrCodeMethodNotFound      = -32009\n\tErrCodeInvalidParams       = -32010\n\tErrCodeInternalError       = -32011\n\tErrCodeNotFound            = -32012\n\tErrCodeUnknownUID          = -32013\n\tErrCodeUnauthorized        = -32014\n\tErrCodeParamsInvalid       = -32015\n)\n\nconst (\n\tparamsEmpty   = \"params can not be empty\"\n\tinvalidParams = \"params %s invalid\"\n)\n\nfunc (e *Error) Error() string {\n\treturn e.Message\n}\n\nfunc NewError(code ErrorCode, message string, data ...map[string]any) *Error {\n\te := Error{\n\t\tCode:    code,\n\t\tMessage: message,\n\t}\n\n\tif len(data) > 0 {\n\t\te.Data = data[0]\n\t}\n\n\treturn &e\n}\n\nfunc DefaultError(message string) *Error {\n\treturn &Error{\n\t\tCode:    ErrCodeDefault,\n\t\tMessage: message,\n\t}\n}\n\nfunc ParseError(message string) *Error {\n\treturn &Error{\n\t\tCode:    ErrCodeParseError,\n\t\tMessage: message,\n\t}\n}\n\nfunc InvalidRequest(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeInvalidRequest, message, data...)\n}\n\nfunc MethodNotFound(method string, data ...map[string]any) *Error {\n\tmessage := fmt.Sprintf(\"The method %s does not exist/is not available\", method)\n\treturn NewError(ErrCodeMethodNotFound, message, data...)\n}\n\nfunc InvalidParamsError(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeInvalidParams, message, data...)\n}\n\nfunc InternalError(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeInternalError, message, data...)\n}\n\nfunc InvalidInput(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeInvalidInput, message, data...)\n}\n\nfunc ResourceNotFound(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeResourceNotFound, message, data...)\n}\n\nfunc ResourceUnavailable(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeResourceUnavailable, message, data...)\n}\n\nfunc TransactionRejected(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeTransactionRejected, message, data...)\n}\n\nfunc MethodNotSupported(method string, data ...map[string]any) *Error {\n\tmessage := fmt.Sprintf(\"method not supported %s\", method)\n\treturn NewError(ErrCodeMethodNotSupported, message, data...)\n}\n\nfunc LimitExceeded(message string, data ...map[string]any) *Error {\n\treturn NewError(ErrCodeLimitExceeded, message, data...)\n}\n\nfunc NotFoundError() *Error {\n\treturn NewError(ErrCodeNotFound, consts.NotFound)\n}\n\nfunc UnauthorizedError() *Error {\n\treturn NewError(ErrCodeUnauthorized, \"Unauthorized\")\n}\n\nfunc UnUnknownUIDError() *Error {\n\treturn NewError(ErrCodeUnknownUID, \"Unknown uid\")\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/handlers.go",
    "content": "package jsonrpc\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\n// RequestHandlerFunc is a helper for handling JSONRPC Requests over HTTP\n// It can be used by microservices to handle JSONRPC methods.  For example:\n//\n//\thttp.Handle(\"/\", RequestHandlerFunc(func(ctx context.Context, r *Request) (interface{}, *Error) {\n//\t\t\tif r.Method != \"eth_blockNumber\" {\n//\t\t\t\treturn nil, MethodNotSupported(fmt.Sprintf(\"unsupported method %s\", r.Method))\n//\t\t\t}\n//\n//\t\t\treturn \"0x123456\", nil\n//\t\t}))\nfunc RequestHandlerFunc(fn requestHandlerFunc) *requestHandlerFunc {\n\treturn &fn\n}\n\ntype RequestContext struct {\n\tcontext.Context\n}\n\nfunc (rc *RequestContext) HTTPRequest() *http.Request {\n\treturn rc.Value(contextKeyHTTPRequest).(*http.Request)\n}\n\nfunc (rc *RequestContext) HTTPResponseWriter() http.ResponseWriter {\n\treturn rc.Value(contextKeyHTTPResponseWriter).(http.ResponseWriter)\n}\n\nfunc (rc *RequestContext) RawJSON() json.RawMessage {\n\treturn rc.Value(contextKeyRawJSON).(json.RawMessage)\n}\n\ntype ctxKey string\n\nfunc (c ctxKey) String() string {\n\treturn \"jsonrpc context key \" + string(c)\n}\n\nvar (\n\tcontextKeyHTTPRequest        = ctxKey(\"HTTP Request\")\n\tcontextKeyHTTPResponseWriter = ctxKey(\"HTTP Response Writer\")\n\tcontextKeyRawJSON            = ctxKey(\"Raw JSON\")\n)\n\ntype requestHandlerFunc func(ctx RequestContext, request *Request) (any, *Error)\n\nfunc (h requestHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\tbuff, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif r.Header.Get(\"Content-Type\") != \"application/json\" {\n\t\thttp.Error(w, \"invalid content type, only application/json is supported\", http.StatusUnsupportedMediaType)\n\t\treturn\n\t}\n\n\trequest := Request{}\n\terr = json.Unmarshal(buff, &request)\n\tif err != nil {\n\t\t// return a generic jsonrpc response\n\t\tWriteResponse(w, nil, nil, InvalidRequest(err.Error()))\n\t\treturn\n\t}\n\n\tctx := context.WithValue(r.Context(), contextKeyHTTPRequest, r)\n\tctx = context.WithValue(ctx, contextKeyRawJSON, json.RawMessage(buff))\n\tctx = context.WithValue(ctx, contextKeyHTTPResponseWriter, w)\n\n\tresult, e := h(RequestContext{ctx}, &request)\n\tWriteResponse(w, &request, result, e)\n}\n\nfunc WriteResponse(w http.ResponseWriter, request *Request, result any, e *Error) {\n\tif result == nil && e == nil {\n\t\treturn\n\t}\n\tresponse := generateResponse(request, result, e)\n\n\tb, err := json.Marshal(response)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.WriteHeader(http.StatusOK)\n\t_, _ = w.Write(b)\n\tif f, ok := w.(http.Flusher); ok {\n\t\tf.Flush()\n\t}\n\n}\n\nfunc generateResponse(request *Request, result any, e *Error) any {\n\tresponse := &Response{\n\t\tJSONRPC: JsonRPCVersion,\n\t}\n\n\tif request != nil {\n\t\tresponse.ID = request.ID\n\t}\n\n\tresponse.Result = result\n\tif e != nil {\n\t\t// NOTE: setting `response.Error = e` if e is nil causes `\"error\": null` to be included\n\t\t// in the Response.  See https://play.golang.org/p/Oe3MFR3wwAu\n\t\tresponse.Error = e\n\t}\n\treturn response\n}\n\nfunc WriteBatchResponse(w http.ResponseWriter, resp any) {\n\tb, err := json.Marshal(resp)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tw.Header().Set(\"content-length\", strconv.Itoa(len(b)))\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t//w.Header().Set(\"transfer-encoding\", \"identity\")\n\tw.WriteHeader(http.StatusOK)\n\t_, _ = w.Write(b)\n\tif f, ok := w.(http.Flusher); ok {\n\t\tf.Flush()\n\t}\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/history.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nconst rollbackHistoryLimit = 100\n\ntype HistoryResult struct {\n\tList []map[string]string `json:\"list\"`\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/http.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"mime\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\nconst (\n\tmaxRequestContentLength = 1024 * 1024 * 5\n\tcontentType             = \"application/json\"\n)\n\nfunc validateRequest(r *http.Request) (int, error) {\n\tif r.Method == http.MethodPut || r.Method == http.MethodDelete {\n\t\treturn http.StatusMethodNotAllowed, errors.New(\"method not allowed\")\n\t}\n\tif r.ContentLength > maxRequestContentLength {\n\t\terr := fmt.Errorf(\"content length too large (%d>%d)\", r.ContentLength, maxRequestContentLength)\n\t\treturn http.StatusRequestEntityTooLarge, err\n\t}\n\t// Allow OPTIONS (regardless of content-type)\n\tif r.Method == http.MethodOptions {\n\t\treturn 0, nil\n\t}\n\t// Check content-type\n\tif mt, _, err := mime.ParseMediaType(r.Header.Get(\"content-type\")); err == nil {\n\t\tif mt == contentType {\n\t\t\treturn 0, nil\n\t\t}\n\t}\n\t// Invalid content-type\n\terr := fmt.Errorf(\"invalid content type, only %s is supported\", contentType)\n\treturn http.StatusUnsupportedMediaType, err\n}\n\nfunc NewMiddlewares(srv http.Handler, m Mode) http.Handler {\n\thandler := newGzipHandler(srv)\n\thandler = clientMiddleware(handler, m)\n\thandler = tokenMiddleware(handler)\n\thandler = nodeStateMiddleware(handler)\n\t//handler = statsdMiddleware(handler)\n\thandler = recoverMiddleware(handler)\n\treturn loggerMiddleware(handler)\n}\n\ntype gzipResponseWriter struct {\n\tresp http.ResponseWriter\n\n\tgz            *gzip.Writer\n\tcontentLength uint64 // total length of the uncompressed response\n\twritten       uint64 // amount of written bytes from the uncompressed response\n\thasLength     bool   // true if uncompressed response had Content-Length\n\thasInit       bool   // true after init was called for the first time\n}\n\nvar gzPool = sync.Pool{\n\tNew: func() interface{} {\n\t\tw := gzip.NewWriter(io.Discard)\n\t\treturn w\n\t},\n}\n\n// init runs just before response headers are written. Among other things, this function\n// also decides whether compression will be applied at all.\nfunc (w *gzipResponseWriter) init() {\n\tif w.hasInit {\n\t\treturn\n\t}\n\tw.hasInit = true\n\n\thdr := w.resp.Header()\n\tlength := hdr.Get(\"content-length\")\n\tif len(length) > 0 {\n\t\tif n, err := strconv.ParseUint(length, 10, 64); err != nil {\n\t\t\tw.hasLength = true\n\t\t\tw.contentLength = n\n\t\t}\n\t}\n\n\t// Setting Transfer-Encoding to \"identity\" explicitly disables compression.\n\tsetIdentity := hdr.Get(\"transfer-encoding\") == \"identity\"\n\tif !setIdentity {\n\t\tw.gz = gzPool.Get().(*gzip.Writer)\n\t\tw.gz.Reset(w.resp)\n\t\thdr.Del(\"content-length\")\n\t\thdr.Set(\"content-encoding\", \"gzip\")\n\t}\n}\n\nfunc (w *gzipResponseWriter) Header() http.Header {\n\treturn w.resp.Header()\n}\n\nfunc (w *gzipResponseWriter) WriteHeader(status int) {\n\tw.init()\n\tw.resp.WriteHeader(status)\n}\n\nfunc (w *gzipResponseWriter) Write(b []byte) (int, error) {\n\tw.init()\n\n\tif w.gz == nil {\n\t\t// Compression is disabled.\n\t\treturn w.resp.Write(b)\n\t}\n\n\tn, err := w.gz.Write(b)\n\tw.written += uint64(n)\n\tif w.hasLength && w.written >= w.contentLength {\n\t\t// The HTTP handler has finished writing the entire uncompressed response. Close\n\t\t// the gzip stream to ensure the footer will be seen by the client in case the\n\t\t// response is flushed after this call to write.\n\t\terr = w.gz.Close()\n\t}\n\treturn n, err\n}\n\nfunc (w *gzipResponseWriter) Flush() {\n\tif w.gz != nil {\n\t\tw.gz.Flush()\n\t}\n\tif f, ok := w.resp.(http.Flusher); ok {\n\t\tf.Flush()\n\t}\n}\n\nfunc (w *gzipResponseWriter) close() {\n\tif w.gz == nil {\n\t\treturn\n\t}\n\tw.gz.Close()\n\tgzPool.Put(w.gz)\n\tw.gz = nil\n}\n\nfunc newGzipHandler(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif !strings.Contains(r.Header.Get(\"Accept-Encoding\"), \"gzip\") {\n\t\t\tnext.ServeHTTP(w, r)\n\t\t\treturn\n\t\t}\n\n\t\twrapper := &gzipResponseWriter{resp: w}\n\t\tdefer wrapper.close()\n\n\t\tnext.ServeHTTP(wrapper, r)\n\t})\n}\n\nfunc ContextRequestTimeout(ctx context.Context) (time.Duration, bool) {\n\ttimeout := time.Duration(math.MaxInt64)\n\thasTimeout := false\n\tsetTimeout := func(d time.Duration) {\n\t\tif d < timeout {\n\t\t\ttimeout = d\n\t\t\thasTimeout = true\n\t\t}\n\t}\n\n\tif deadline, ok := ctx.Deadline(); ok {\n\t\tsetTimeout(time.Until(deadline))\n\t}\n\n\t// If the context is an HTTP request context, use the server's WriteTimeout.\n\thttpSrv, ok := ctx.Value(http.ServerContextKey).(*http.Server)\n\tif ok && httpSrv.WriteTimeout > 0 {\n\t\twt := httpSrv.WriteTimeout\n\t\t// When a write timeout is configured, we need to send the response message before\n\t\t// the HTTP server cuts connection. So our internal timeout must be earlier than\n\t\t// the server's true timeout.\n\t\t//\n\t\t// Note: Timeouts are sanitized to be a minimum of 1 second.\n\t\t// Also see issue: https://github.com/golang/go/issues/47229\n\t\twt -= 100 * time.Millisecond\n\t\tsetTimeout(wt)\n\t}\n\n\treturn timeout, hasTimeout\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/id.go",
    "content": "package jsonrpc\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n)\n\n// ID represents a JSON-RPC 2.0 request ID, which may be either a\n// string or number (or null, which is unsupported).\ntype ID struct {\n\t// At most one of Num or Str may be nonzero. If both are zero\n\t// valued, then IsNum specifies which field's value is to be used\n\t// as the ID.\n\tNum uint64\n\tStr string\n\n\t// IsString controls whether the Num or Str field's value should be\n\t// used as the ID, when both are zero valued. It must always be\n\t// set to true if the request ID is a string.\n\tIsString bool\n}\n\nfunc StringID(s string) ID {\n\treturn ID{\n\t\tStr:      s,\n\t\tIsString: true,\n\t}\n}\n\nfunc IntID(i uint64) ID {\n\treturn ID{\n\t\tNum:      i,\n\t\tIsString: false,\n\t}\n}\n\nfunc (id ID) String() string {\n\tif id.IsString {\n\t\treturn strconv.Quote(id.Str)\n\t}\n\treturn strconv.FormatUint(id.Num, 10)\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (id ID) MarshalJSON() ([]byte, error) {\n\tif id.IsString {\n\t\treturn json.Marshal(id.Str)\n\t}\n\treturn json.Marshal(id.Num)\n}\n\n// UnmarshalJSON implements json.Unmarshaler.\nfunc (id *ID) UnmarshalJSON(data []byte) error {\n\t// Support both uint64 and string IDs.\n\tvar v uint64\n\tif err := json.Unmarshal(data, &v); err == nil {\n\t\t*id = ID{Num: v}\n\t\treturn nil\n\t}\n\tvar v2 string\n\tif err := json.Unmarshal(data, &v2); err != nil {\n\t\treturn err\n\t}\n\t*id = ID{Str: v2, IsString: true}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/jwt.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/golang-jwt/jwt/v4\"\n\t\"strings\"\n)\n\nvar (\n\tjwtSecret       []byte\n\tjwtPrefix       = \"Bearer \"\n\tjwtExpire       = 28800 // By default, seconds\n\tjwtrefeshExpire = 600   // By default, seconds\n\n\terrJWTAuthValue      = errors.New(\"wrong authorization value\")\n\terrEcosystemNotFound = errors.New(\"ecosystem not found\")\n)\n\n// JWTClaims is storing jwt claims\ntype JWTClaims struct {\n\tUID         string `json:\"uid,omitempty\"`\n\tEcosystemID string `json:\"ecosystem_id,omitempty\"`\n\tKeyID       string `json:\"key_id,omitempty\"`\n\tAccountID   string `json:\"account_id,omitempty\"`\n\tRoleID      string `json:\"role_id,omitempty\"`\n\tjwt.RegisteredClaims\n}\n\nfunc generateJWTToken(claims JWTClaims) (string, error) {\n\ttoken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n\treturn token.SignedString(jwtSecret)\n}\n\nfunc parseJWTToken(header string) (*jwt.Token, error) {\n\tif len(header) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tif strings.HasPrefix(header, jwtPrefix) {\n\t\theader = header[len(jwtPrefix):]\n\t} else {\n\t\treturn nil, errJWTAuthValue\n\t}\n\n\treturn jwt.ParseWithClaims(header, &JWTClaims{}, func(token *jwt.Token) (any, error) {\n\t\tif _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {\n\t\t\treturn nil, fmt.Errorf(\"Unexpected signing method: %v\", token.Header[\"alg\"])\n\t\t}\n\t\treturn []byte(jwtSecret), nil\n\t})\n}\n\nfunc getClientFromToken(token *jwt.Token, ecosysNameService types.EcosystemGetter) (*UserClient, error) {\n\tclaims, ok := token.Claims.(*JWTClaims)\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\tif len(claims.KeyID) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tclient := &UserClient{\n\t\tEcosystemID: converter.StrToInt64(claims.EcosystemID),\n\t\tKeyID:       converter.StrToInt64(claims.KeyID),\n\t\tAccountID:   claims.AccountID,\n\t\tRoleID:      converter.StrToInt64(claims.RoleID),\n\t}\n\n\tsID := converter.StrToInt64(claims.EcosystemID)\n\tname, err := ecosysNameService.GetEcosystemName(sID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient.EcosystemName = name\n\treturn client, nil\n}\n\nfunc InitJwtSecret(secret []byte) {\n\tif secret == nil {\n\t\tpanic(\"[JSON-RPC] jwt secret invalid\")\n\t}\n\tjwtSecret = secret\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/middlewares.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n\t\"github.com/IBAX-io/go-ibax/packages/statsd\"\n\t\"github.com/didip/tollbooth\"\n\t\"github.com/gorilla/mux\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"net/http\"\n\t\"runtime/debug\"\n\t\"time\"\n)\n\nfunc clientMiddleware(next http.Handler, m Mode) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\ttoken := getToken(r)\n\t\tvar client *UserClient\n\t\tif token != nil { // get client from token\n\t\t\tvar err error\n\t\t\tif client, err = getClientFromToken(token, m.EcosystemGetter); err != nil {\n\t\t\t\tWriteResponse(w, nil, nil, DefaultError(err.Error()))\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tif client == nil {\n\t\t\t// create client with default ecosystem\n\t\t\tclient = &UserClient{EcosystemID: 1}\n\t\t}\n\t\tr = setClient(r, client)\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc loggerFromRequest(r *http.Request) *log.Entry {\n\treturn log.WithFields(log.Fields{\n\t\t\"headers\":  r.Header,\n\t\t\"path\":     r.URL.Path,\n\t\t\"protocol\": r.Proto,\n\t\t\"remote\":   r.RemoteAddr,\n\t})\n}\nfunc loggerMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tlogger := loggerFromRequest(r)\n\t\tlogger.Info(\"received http request\")\n\t\tr = setLogger(r, logger)\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc recoverMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tdefer func() {\n\t\t\tif err := recover(); err != nil {\n\t\t\t\tlogger := getLogger(r)\n\t\t\t\tlogger.WithFields(log.Fields{\n\t\t\t\t\t\"type\":  consts.PanicRecoveredError,\n\t\t\t\t\t\"error\": err,\n\t\t\t\t\t\"stack\": string(debug.Stack()),\n\t\t\t\t}).Debug(\"panic recovered error\")\n\t\t\t\tWriteResponse(w, nil, nil, InternalError(\"JSON RPC API recovered\"))\n\t\t\t}\n\t\t}()\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc nodeStateMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch node.NodePauseType() {\n\t\tcase node.NoPause:\n\t\t\tnext.ServeHTTP(w, r)\n\t\t\treturn\n\t\tcase node.PauseTypeUpdatingBlockchain:\n\t\t\tWriteResponse(w, nil, nil, DefaultError(\"Node is updating blockchain\"))\n\t\t\tbreak\n\t\tcase node.PauseTypeStopingNetwork:\n\t\t\tWriteResponse(w, nil, nil, DefaultError(\"Network is stopping\"))\n\t\t\tbreak\n\t\t}\n\t})\n}\n\nfunc tokenMiddleware(next http.Handler) http.Handler {\n\tconst authHeader = \"AUTHORIZATION\"\n\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t//token, err := RefreshToken(r.Header.Get(authHeader))\n\t\ttoken, err := parseJWTToken(r.Header.Get(authHeader))\n\t\tif err != nil {\n\t\t\tlogger := getLogger(r)\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JWTError, \"error\": err}).Warning(\"starting session\")\n\t\t}\n\t\tif token != nil && token.Valid {\n\t\t\tr = setToken(r, token)\n\t\t}\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc statsdMiddleware(next http.Handler) http.Handler {\n\tconst v = 1.0\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t//request url\n\t\troute := mux.CurrentRoute(r)\n\n\t\tcounterName := statsd.APIRouteCounterName(r.Method, route.GetName())\n\t\tstatsd.Client.Inc(counterName+statsd.Count, 1, v)\n\t\tstartTime := time.Now()\n\n\t\tdefer func() {\n\t\t\tstatsd.Client.TimingDuration(counterName+statsd.Time, time.Since(startTime), v)\n\t\t}()\n\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n\nfunc limiterMiddleware(next http.Handler) http.Handler {\n\t//max ten requests per second\n\tlimiter := tollbooth.NewLimiter(10, nil)\n\treturn tollbooth.LimitHandler(limiter, next)\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/namespace.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"reflect\"\n)\n\ntype space string\n\nconst (\n\tnamespaceSeparator = \".\"\n)\n\nconst (\n\tnamespaceRPC   space = \"rpc\"\n\tNamespaceDebug space = \"debug\"\n\n\tNamespaceIBAX  space = \"ibax\"\n\tNamespaceAdmin space = \"admin\"\n\tNamespaceNet   space = \"net\"\n)\n\ntype RpcApis interface {\n\tGetApis() []any\n}\n\ntype RpcServers struct {\n\tserver *Server\n}\n\ntype NewApiService interface {\n\tNew(structObject any) (name string)\n\tDelete(name string)\n}\n\ntype Method struct {\n\tservices map[string]reflect.Value\n}\n\nfunc (a *Method) Delete(name string) {\n\tfor k, _ := range a.services {\n\t\tif k == name {\n\t\t\tdelete(a.services, k)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (a *Method) New(structObject any) (name string) {\n\tif a.services == nil {\n\t\ta.services = make(map[string]reflect.Value)\n\t}\n\tvar findOut bool\n\tref := GetStructValue(structObject)\n\tfor _, v := range a.services {\n\t\tif v == ref {\n\t\t\tfindOut = true\n\t\t}\n\t}\n\tname = ref.Type().String()\n\tif !findOut {\n\t\ta.services[name] = ref\n\t}\n\treturn\n}\n\nfunc (r *RpcServers) Modules() ([]string, *Error) {\n\tr.server.service.mu.Lock()\n\tdefer r.server.service.mu.Unlock()\n\tvar methods []string\n\tfor namespace, v := range r.server.service.services {\n\t\tfor name := range v.callbacks {\n\t\t\tmethods = append(methods, namespace+namespaceSeparator+name)\n\t\t}\n\t}\n\treturn methods, nil\n}\n\nfunc GetStructValue(structObject any) reflect.Value {\n\treturn reflect.ValueOf(structObject)\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/namespace_debug.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\ntype DebugApi struct {\n\tde *debugApi\n}\n\nfunc (p *DebugApi) GetApis() []any {\n\tvar apis []any\n\tif p == nil {\n\t\treturn nil\n\t}\n\tif p.de != nil {\n\t\tapis = append(apis, p.de)\n\t}\n\n\treturn apis\n}\n\nfunc NewDebugApi() *DebugApi {\n\treturn &DebugApi{\n\t\tde: newDebugApi(),\n\t}\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/namespace_ibax.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\ntype IbaxApi struct {\n\tauth    *authApi\n\tbk      *blockChainApi\n\tcommon  *commonApi\n\ttx      *transactionApi\n\taccount *accountsApi\n\tdata    *dataApi\n}\n\nfunc (p *IbaxApi) GetApis() []any {\n\tvar apis []any\n\tif p == nil {\n\t\treturn nil\n\t}\n\tif p.auth != nil {\n\t\tapis = append(apis, p.auth)\n\t}\n\tif p.bk != nil {\n\t\tapis = append(apis, p.bk)\n\t}\n\tif p.common != nil {\n\t\tapis = append(apis, p.common)\n\t}\n\tif p.tx != nil {\n\t\tapis = append(apis, p.tx)\n\t}\n\tif p.account != nil {\n\t\tapis = append(apis, p.account)\n\t}\n\tif p.data != nil {\n\t\tapis = append(apis, p.data)\n\t}\n\treturn apis\n}\n\nfunc NewIbaxApi(m Mode) *IbaxApi {\n\treturn &IbaxApi{\n\t\tauth:    newAuthApi(m),\n\t\tbk:      newBlockChainApi(),\n\t\tcommon:  newCommonApi(m),\n\t\ttx:      newTransactionApi(),\n\t\taccount: newAccountsApi(m),\n\t\tdata:    newDataApi(),\n\t}\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/namespace_net.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/service/node\"\n)\n\ntype NetApi struct {\n\tnet *networkApi\n}\n\nfunc NewNetApi() *NetApi {\n\treturn &NetApi{\n\t\tnet: NewNetworkApi(),\n\t}\n}\n\nfunc (p *NetApi) GetApis() []any {\n\tvar apis []any\n\tif p == nil {\n\t\treturn nil\n\t}\n\tif p.net != nil {\n\t\tapis = append(apis, p.net)\n\t}\n\treturn apis\n}\n\ntype networkApi struct {\n}\n\nfunc NewNetworkApi() *networkApi {\n\tn := &networkApi{}\n\treturn n\n}\n\nfunc (n *networkApi) Status() string {\n\treturn node.NodePauseType().String()\n}\n\nfunc (c *networkApi) GetNetwork() (*NetworkResult, *Error) {\n\treturn &NetworkResult{\n\t\tNetworkID:     converter.Int64ToStr(conf.Config.LocalConf.NetworkID),\n\t\tCentrifugoURL: conf.Config.Centrifugo.URL,\n\t\tTest:          syspar.IsTestMode(),\n\t\tPrivate:       syspar.IsPrivateBlockchain(),\n\t\tHonorNodes:    getNodesJSON(),\n\t}, nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/params.go",
    "content": "package jsonrpc\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/pkg/errors\"\n)\n\n// Params is an ARRAY of json.RawMessages.  This is because *Ethereum* RPCs always use\n// arrays is their input parameter; this differs from the official JSONRPC spec, which allows\n// parameters of any type.\n// But, this assumption makes handling Params in our Ethereum API use-cases *so* much easier.\ntype Param json.RawMessage\ntype Params []Param\n\n// MarshalJSON returns m as the JSON encoding of m.\nfunc (m Param) MarshalJSON() ([]byte, error) {\n\tif m == nil {\n\t\treturn []byte(\"null\"), nil\n\t}\n\treturn m, nil\n}\n\n// UnmarshalJSON sets *m to a copy of data.\nfunc (m *Param) UnmarshalJSON(data []byte) error {\n\tif m == nil {\n\t\treturn errors.New(\"json.RawMessage: UnmarshalJSON on nil pointer\")\n\t}\n\t*m = append((*m)[0:0], data...)\n\treturn nil\n}\n\n// MustParams can be used to generate JSONRPC Params field from well-known\n// data, which should not fail.\n//\n// Examples:\n//\n//\trequest.Params = jsonrpc.MustParams(\"latest\", true)\nfunc MustParams(params ...any) Params {\n\tout, err := MakeParams(params...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn out\n}\n\n// MakeParams generates JSONRPC parameters from its inputs, and should be used for\n// complex dynamic data which may fail to marshal, in which case the error is propagated\n// to the caller.\n//\n// Examples:\n//\n//\tparams, err := jsonrpc.MakeParams(someComplexObject, \"string\", true)\nfunc MakeParams(params ...any) (Params, error) {\n\tif len(params) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tout := make(Params, len(params))\n\tfor i, param := range params {\n\t\tb, err := json.Marshal(param)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tout[i] = Param(b)\n\t}\n\treturn out, nil\n}\n\n// UnmarshalInto will decode Params into the passed in values, which\n// must be pointer receivers.  The type of the passed in value is used to Unmarshal the data.\n// UnmarshalInto will fail if the parameters cannot be converted to the passed-in types.\n//\n// Example:\n//\n//\tvar blockNum string\n//\tvar fullBlock bool\n//\terr := request.Params.UnmarshalInto(&blockNum, &fullBlock)\n//\n// IMPORTANT: While Go will compile with non-pointer receivers, the Unmarshal attempt will\n// *always* fail with an error.\nfunc (p Params) UnmarshalInto(receivers ...any) error {\n\tif p == nil {\n\t\treturn nil\n\t}\n\n\tif len(p) < len(receivers) {\n\t\treturn errors.New(\"not enough params to decode\")\n\t}\n\n\tfor i, r := range receivers {\n\t\terr := json.Unmarshal(p[i], r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p Params) UnmarshalValue(types []reflect.Type) (args []reflect.Value, err error) {\n\tdefer func() {\n\t\tif err == nil {\n\t\t\t//Set any missing args to nil. prevent fn call panic\n\t\t\tfor i := len(args); i < len(types); i++ {\n\t\t\t\tif types[i].Kind() != reflect.Ptr {\n\t\t\t\t\targs = nil\n\t\t\t\t\terr = fmt.Errorf(\"missing value for required argument %d\", i+1)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\targs = append(args, reflect.Zero(types[i]))\n\t\t\t}\n\t\t}\n\t}()\n\tif p == nil {\n\t\treturn nil, nil\n\t}\n\tif len(p) > len(types) {\n\t\treturn nil, errors.New(fmt.Sprintf(\"too many arguments, want %d\", len(types)))\n\t}\n\n\targs = make([]reflect.Value, 0, len(types))\n\tfor i, _ := range p {\n\t\tdec := json.NewDecoder(bytes.NewReader(p[i]))\n\t\targval := reflect.New(types[i])\n\t\tif err := dec.Decode(argval.Interface()); err != nil {\n\t\t\treturn args, fmt.Errorf(\"invalid argument %d: %v\", i+1, err)\n\t\t}\n\t\tif argval.IsNil() && types[i].Kind() != reflect.Ptr {\n\t\t\treturn args, fmt.Errorf(\"missing value for required argument %d\", i+1)\n\t\t}\n\t\targs = append(args, argval.Elem())\n\t}\n\n\treturn args, nil\n}\n\n// UnmarshalSingleParam can be used in the (rare) case where only one of the Request.Params is\n// needed.  For example we use this in Smart Routing to extract the blockNum value from RPCs without\n// decoding the entire Params array.\n//\n// Example:\n//\n//\terr := request.Params.UnmarshalSingleParam(pos, &blockNum)\nfunc (p Params) UnmarshalSingleParam(pos int, receiver any) error {\n\tif pos > (len(p) - 1) {\n\t\treturn errors.New(\"not enough parameters to decode position\")\n\t}\n\n\tparam := p[pos]\n\terr := json.Unmarshal(param, receiver)\n\treturn err\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/raw_response.go",
    "content": "package jsonrpc\n\nimport (\n\t\"encoding/json\"\n)\n\n// RawResponse keeps Result and Error as unparsed JSON\n// It is meant to be used to deserialize JSONPRC responses from downstream components\n// while Response is meant to be used to craft our own responses to clients.\ntype RawResponse struct {\n\tJSONRPC string           `json:\"jsonrpc\"`\n\tID      ID               `json:\"id\"`\n\tResult  json.RawMessage  `json:\"result,omitempty\"`\n\tError   *json.RawMessage `json:\"error,omitempty\"`\n}\n\n// MarshalJSON implements json.Marshaler and adds the \"jsonrpc\":\"2.0\"\n// property.\nfunc (r RawResponse) MarshalJSON() ([]byte, error) {\n\n\tif r.Error != nil {\n\t\tresponse := struct {\n\t\t\tJSONRPC string          `json:\"jsonrpc\"`\n\t\t\tID      ID              `json:\"id\"`\n\t\t\tError   json.RawMessage `json:\"error,omitempty\"`\n\t\t}{\n\t\t\tJSONRPC: JsonRPCVersion,\n\t\t\tID:      r.ID,\n\t\t\tError:   *r.Error,\n\t\t}\n\n\t\treturn json.Marshal(response)\n\t} else {\n\t\tresponse := struct {\n\t\t\tJSONRPC string          `json:\"jsonrpc\"`\n\t\t\tID      ID              `json:\"id\"`\n\t\t\tResult  json.RawMessage `json:\"result,omitempty\"`\n\t\t}{\n\t\t\tJSONRPC: JsonRPCVersion,\n\t\t\tID:      r.ID,\n\t\t\tResult:  r.Result,\n\t\t}\n\n\t\tif response.Result == nil {\n\t\t\tresponse.Result = jsonNull\n\t\t}\n\n\t\treturn json.Marshal(response)\n\t}\n}\n\n// UnmarshalJSON implements json.Unmarshaler.\nfunc (r *RawResponse) UnmarshalJSON(data []byte) error {\n\ttype tmpType RawResponse\n\n\tif err := json.Unmarshal(data, (*tmpType)(r)); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/request.go",
    "content": "package jsonrpc\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"github.com/pkg/errors\"\n\t\"io\"\n)\n\nconst JsonRPCVersion = \"2.0\"\n\ntype Request struct {\n\tJSONRPC string `json:\"jsonrpc\"`\n\tMethod  string `json:\"method\"`\n\tID      ID     `json:\"id\"`\n\tParams  Params `json:\"params\"`\n}\n\ntype BatchRequest []*Request\n\ntype RequestWithNetwork struct {\n\t*Request\n\tNetwork string `json:\"network\"`\n}\n\nfunc NewRequest() *Request {\n\treturn &Request{JSONRPC: JsonRPCVersion, ID: ID{Num: 1}}\n}\n\n// MakeRequest builds a Request from all its parts, but returns an error if the\n// params cannot be marshalled.\nfunc MakeRequest(id int, method string, params ...any) (*Request, error) {\n\tp, err := MakeParams(params...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Request{\n\t\tJSONRPC: JsonRPCVersion,\n\t\tID:      ID{Num: uint64(id)},\n\t\tMethod:  method,\n\t\tParams:  p,\n\t}, nil\n}\n\n// MustRequest builds a request from all its parts but panics if the params cannot be marshaled,\n// so should only be used with well-known parameter data.\nfunc MustRequest(id int, method string, params ...any) *Request {\n\tr, err := MakeRequest(id, method, params...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn r\n}\n\n// MarshalJSON implements json.Marshaler and adds the \"jsonrpc\":\"2.0\"\n// property.\nfunc (r Request) MarshalJSON() ([]byte, error) {\n\tr2 := struct {\n\t\tMethod  string `json:\"method\"`\n\t\tParams  Params `json:\"params,omitempty\"`\n\t\tID      *ID    `json:\"id,omitempty\"`\n\t\tJSONRPC string `json:\"jsonrpc\"`\n\t}{\n\t\tMethod:  r.Method,\n\t\tParams:  r.Params,\n\t\tJSONRPC: JsonRPCVersion,\n\t}\n\tr2.ID = &r.ID\n\treturn json.Marshal(r2)\n}\n\n// UnmarshalJSON implements json.Unmarshaler.\nfunc (r *Request) UnmarshalJSON(data []byte) error {\n\tvar r2 struct {\n\t\tMethod string           `json:\"method\"`\n\t\tParams *json.RawMessage `json:\"params,omitempty\"`\n\t\tMeta   *json.RawMessage `json:\"meta,omitempty\"`\n\t\tID     *ID              `json:\"id\"`\n\t}\n\n\t// Detect if the \"params\" field is JSON \"null\" or just not present\n\t// by seeing if the field gets overwritten to nil.\n\tr2.Params = &json.RawMessage{}\n\n\tif err := json.Unmarshal(data, &r2); err != nil {\n\t\treturn err\n\t}\n\tr.Method = r2.Method\n\tif r2.Params == nil {\n\t\tr.Params = nil\n\t} else if len(*r2.Params) == 0 {\n\t\tr.Params = nil\n\t} else {\n\t\terr := json.Unmarshal(*r2.Params, &r.Params)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif r2.Method == \"\" {\n\t\treturn errors.New(\"request is missing method\")\n\t}\n\n\tif r2.ID == nil {\n\t\treturn errors.New(\"request is missing ID\")\n\t} else {\n\t\tr.ID = *r2.ID\n\t}\n\n\tr.JSONRPC = JsonRPCVersion\n\treturn nil\n}\n\nfunc getBatch(r io.ReadCloser, ctxer func(json.RawMessage)) (reqs []*Request, batch bool, err error) {\n\tbody := io.LimitReader(r, maxRequestContentLength)\n\tdec := json.NewDecoder(body)\n\tdec.UseNumber()\n\n\tvar raw json.RawMessage\n\terr = dec.Decode(&raw)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\tctxer(raw)\n\treqs, batch = parseRequest(raw)\n\tfor k, req := range reqs {\n\t\tif req == nil {\n\t\t\treqs[k] = &Request{}\n\t\t}\n\t}\n\treturn reqs, batch, nil\n}\n\nfunc parseRequest(raw json.RawMessage) ([]*Request, bool) {\n\tif !isBatch(raw) {\n\t\treqs := []*Request{{}}\n\t\tjson.Unmarshal(raw, &reqs[0])\n\t\treturn reqs, false\n\t}\n\tdec := json.NewDecoder(bytes.NewReader(raw))\n\tdec.Token() // skip '['\n\tvar reqs []*Request\n\tfor dec.More() {\n\t\treqs = append(reqs, new(Request))\n\t\tdec.Decode(&reqs[len(reqs)-1])\n\t}\n\treturn reqs, true\n}\n\nfunc isBatch(raw json.RawMessage) bool {\n\tfor _, c := range raw {\n\t\t// skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt)\n\t\tif c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d {\n\t\t\tcontinue\n\t\t}\n\t\treturn c == '['\n\t}\n\treturn false\n}\n\n// MarshalJSON implements json.Marshaler and adds the \"jsonrpc\":\"2.0\"\n// property.\nfunc (r RequestWithNetwork) MarshalJSON() ([]byte, error) {\n\tr2 := struct {\n\t\tMethod  string `json:\"method\"`\n\t\tParams  Params `json:\"params,omitempty\"`\n\t\tID      *ID    `json:\"id,omitempty\"`\n\t\tJSONRPC string `json:\"jsonrpc\"`\n\t\tNetwork string `json:\"network\"`\n\t}{\n\t\tMethod:  r.Method,\n\t\tParams:  r.Params,\n\t\tNetwork: r.Network,\n\t\tJSONRPC: JsonRPCVersion,\n\t}\n\tr2.ID = &r.ID\n\treturn json.Marshal(r2)\n}\n\n// UnmarshalJSON implements json.Unmarshaler.\nfunc (r *RequestWithNetwork) UnmarshalJSON(data []byte) error {\n\tvar r2 struct {\n\t\tMethod  string           `json:\"method\"`\n\t\tParams  *json.RawMessage `json:\"params,omitempty\"`\n\t\tMeta    *json.RawMessage `json:\"meta,omitempty\"`\n\t\tNetwork string           `json:\"network\"`\n\t\tID      *ID              `json:\"id\"`\n\t}\n\n\t// Detect if the \"params\" field is JSON \"null\" or just not present\n\t// by seeing if the field gets overwritten to nil.\n\tr2.Params = &json.RawMessage{}\n\tr2.Network = r.Network\n\n\tif err := json.Unmarshal(data, &r2); err != nil {\n\t\treturn err\n\t}\n\tr.Method = r2.Method\n\tif r2.Params == nil {\n\t\tr.Params = nil\n\t} else if len(*r2.Params) == 0 {\n\t\tr.Params = nil\n\t} else {\n\t\terr := json.Unmarshal(*r2.Params, &r.Params)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif r2.ID == nil {\n\t\treturn errors.New(\"request is missing ID\")\n\t} else {\n\t\tr.ID = *r2.ID\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/response.go",
    "content": "package jsonrpc\n\nimport (\n\t\"encoding/json\"\n)\n\nvar (\n\tjsonNull = json.RawMessage(\"null\")\n)\n\ntype Response struct {\n\tJSONRPC string `json:\"jsonrpc\"`\n\tID      ID     `json:\"id\"`\n\tResult  any    `json:\"result,omitempty\"`\n\tError   any    `json:\"error,omitempty\"`\n}\n\ntype BatchResponse []*Response\n\nfunc NewResponse() *Response {\n\treturn &Response{}\n}\n\n// MarshalJSON implements json.Marshaler and adds the \"jsonrpc\":\"2.0\"\n// property.\nfunc (r Response) MarshalJSON() ([]byte, error) {\n\n\tif r.Error != nil {\n\t\tresponse := struct {\n\t\t\tJSONRPC string `json:\"jsonrpc\"`\n\t\t\tID      ID     `json:\"id\"`\n\t\t\tError   any    `json:\"error,omitempty\"`\n\t\t}{\n\t\t\tJSONRPC: JsonRPCVersion,\n\t\t\tID:      r.ID,\n\t\t\tError:   r.Error,\n\t\t}\n\n\t\treturn json.Marshal(response)\n\t} else {\n\t\tresponse := struct {\n\t\t\tJSONRPC string `json:\"jsonrpc\"`\n\t\t\tID      ID     `json:\"id\"`\n\t\t\tResult  any    `json:\"result,omitempty\"`\n\t\t}{\n\t\t\tJSONRPC: JsonRPCVersion,\n\t\t\tID:      r.ID,\n\t\t\tResult:  r.Result,\n\t\t}\n\n\t\tif response.Result == nil {\n\t\t\tresponse.Result = jsonNull\n\t\t}\n\n\t\treturn json.Marshal(response)\n\t}\n}\n\n// UnmarshalJSON implements json.Unmarshaler.\nfunc (r *Response) UnmarshalJSON(data []byte) error {\n\ttype tmpType Response\n\n\tif err := json.Unmarshal(data, (*tmpType)(r)); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/server.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"fmt\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"net/http\"\n\t\"sync/atomic\"\n)\n\ntype Server struct {\n\tservice serviceRegistry\n\tstatus  int32\n}\n\nfunc (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\t// Permit dumb empty requests for remote health-checks (AWS)\n\tif r.Method == http.MethodGet && r.ContentLength == 0 && r.URL.RawQuery == \"\" {\n\t\tw.WriteHeader(http.StatusOK)\n\t\treturn\n\t}\n\n\tif code, err := validateRequest(r); err != nil {\n\t\thttp.Error(w, err.Error(), code)\n\t\treturn\n\t}\n\tif atomic.LoadInt32(&s.status) == 0 {\n\t\treturn\n\t}\n\n\ts.service.ServeHTTP(w, r)\n}\n\nfunc NewServer(m Mode) *Server {\n\tserver := &Server{\n\t\tstatus: 1,\n\t}\n\tserver.service.mode = m\n\n\trpcService := &RpcServers{server}\n\n\tname := GetNamespace(namespaceRPC)\n\terr := server.RegisterName(name, rpcService)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"register name[%s] failed:%s\\n\", name, err.Error()))\n\t}\n\n\treturn server\n}\n\nfunc (s *Server) RegisterName(namespace string, function any) error {\n\treturn s.service.registerName(namespace, function)\n}\n\nfunc (s *Server) Stop() {\n\ts.service.mu.Lock()\n\tdefer s.service.mu.Unlock()\n\n\tif atomic.CompareAndSwapInt32(&s.status, 1, 0) {\n\t\tlog.Debug(\"Json-RPC server shutting down\")\n\t}\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/service.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype service struct {\n\tcallbacks map[string]*callback // registered handlers\n}\n\ntype serviceRegistry struct {\n\tmu       sync.Mutex\n\tservices map[string]service\n\troute    func(ctx RequestContext, request *Request)\n\tmode     Mode\n\tctx      context.Context\n\tcancel   context.CancelFunc\n\trunWg    sync.WaitGroup\n\tt1       time.Time\n}\n\nfunc (r *serviceRegistry) registerName(namespace string, stct any) error {\n\tstctVal := GetStructValue(stct)\n\tif namespace == \"\" {\n\t\treturn fmt.Errorf(\"no service name for type %s\", stctVal.Type().String())\n\t}\n\tcallbacks := suitableCallbacks(stctVal)\n\tif len(callbacks) == 0 {\n\t\treturn fmt.Errorf(\"service %T doesn't have any suitable methods/subscriptions to expose\", stct)\n\t}\n\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\tif r.services == nil {\n\t\tr.services = make(map[string]service)\n\t}\n\tsvc, ok := r.services[namespace]\n\tif !ok {\n\t\tsvc = service{\n\t\t\tcallbacks: make(map[string]*callback),\n\t\t}\n\t\tr.services[namespace] = svc\n\t}\n\tfor name, cb := range callbacks {\n\t\tsvc.callbacks[name] = cb\n\t}\n\treturn nil\n}\n\n// ServeHTTP json-rpc server\nfunc (s *serviceRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\ts.t1 = time.Now()\n\tctx := context.WithValue(r.Context(), contextKeyHTTPRequest, r)\n\tctx = context.WithValue(ctx, contextKeyHTTPResponseWriter, w)\n\tctxer := func(raw json.RawMessage) {\n\t\tctx = context.WithValue(ctx, contextKeyRawJSON, raw)\n\t}\n\treqs, batch, err := getBatch(r.Body, ctxer)\n\tif err != nil {\n\t\tif err != io.EOF {\n\t\t\tWriteResponse(w, nil, nil, InvalidParamsError(err.Error()))\n\t\t\treturn\n\t\t}\n\t}\n\ts.ctx, s.cancel = context.WithCancel(ctx)\n\tdefer s.close(io.EOF)\n\n\tif batch {\n\t\tif len(reqs) == 0 {\n\t\t\tWriteResponse(w, nil, nil, InvalidInput(\"empty batch request\"))\n\t\t\treturn\n\t\t}\n\t\ts.runBatch(RequestContext{ctx}, reqs)\n\t\treturn\n\t}\n\n\tresult, e := s.run(RequestContext{ctx}, false, reqs)\n\tWriteResponse(w, reqs[0], result, e)\n}\n\nfunc (s *serviceRegistry) close(err error) {\n\ts.runWg.Wait()\n\ts.cancel()\n}\n\nfunc GetNamespace(name space) string {\n\treturn string(name)\n}\n\nfunc (r *serviceRegistry) findCallback(method string) *callback {\n\telem := strings.SplitN(method, namespaceSeparator, 2)\n\tif len(elem) != 2 {\n\t\treturn nil\n\t}\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\treturn r.services[elem[0]].callbacks[elem[1]]\n}\n\nfunc (s *serviceRegistry) run(ctx RequestContext, isBatch bool, reqs []*Request) (any, *Error) {\n\treq := reqs[0]\n\tcb := s.findCallback(req.Method)\n\tif cb == nil {\n\t\treturn nil, MethodNotFound(req.Method)\n\t}\n\tif cb.hasAuth {\n\t\tr := ctx.HTTPRequest()\n\t\tif err := authRequire(r); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif cb.notSingle && isBatch {\n\t\treturn nil, InvalidInput(\"not support batch\")\n\t}\n\targs, err := req.Params.UnmarshalValue(cb.argTypes)\n\tif err != nil {\n\t\treturn nil, InvalidParamsError(err.Error())\n\t}\n\n\treturn runMethod(ctx, s.mode, args, cb)\n}\n\nfunc runMethod(ctx RequestContext, m Mode, args []reflect.Value, cb *callback) (any, *Error) {\n\treturn cb.call(ctx, m, args)\n}\n\nfunc (s *serviceRegistry) runBatch(reqCtx RequestContext, reqs []*Request) {\n\ts.callProc(func(ctx context.Context) {\n\t\tvar (\n\t\t\ttimer      *time.Timer\n\t\t\tcancel     context.CancelFunc\n\t\t\tcallBuffer = &batchCallBuffer{reqs: reqs, resp: make([]*any, 0, len(reqs))}\n\t\t)\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tdefer cancel()\n\t\tif timeout, ok := ContextRequestTimeout(ctx); ok {\n\t\t\ttimer = time.AfterFunc(timeout, func() {\n\t\t\t\tcancel()\n\t\t\t\tcallBuffer.write(reqCtx, true)\n\t\t\t})\n\t\t}\n\t\tfor {\n\t\t\t// No need to handle rest of reqs if timed out.\n\t\t\tif ctx.Err() != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tmsg := callBuffer.nextRequest()\n\t\t\tif msg == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treq := []*Request{msg}\n\t\t\tresp, err := s.run(reqCtx, true, req)\n\t\t\tcallBuffer.pushResponse(&resp, err, msg)\n\t\t}\n\t\tif timer != nil {\n\t\t\ttimer.Stop()\n\t\t}\n\t\tcallBuffer.write(reqCtx, false)\n\t})\n\n}\n\nfunc (s *serviceRegistry) callProc(fn func(ctx context.Context)) {\n\ts.runWg.Add(1)\n\tgo func() {\n\t\tctx, cancel := context.WithCancel(s.ctx)\n\t\tdefer s.runWg.Done()\n\t\tdefer cancel()\n\t\tfn(ctx)\n\t}()\n}\n\ntype batchCallBuffer struct {\n\tmutex sync.Mutex\n\treqs  []*Request\n\tresp  []*any\n\twrote bool\n}\n\n// nextRequest returns the next unprocessed request.\nfunc (b *batchCallBuffer) nextRequest() *Request {\n\tb.mutex.Lock()\n\tdefer b.mutex.Unlock()\n\n\tif len(b.reqs) == 0 {\n\t\treturn nil\n\t}\n\treq := b.reqs[0]\n\treturn req\n}\n\n// pushResponse add the response.\nfunc (b *batchCallBuffer) pushResponse(answer *any, err *Error, req *Request) {\n\tb.mutex.Lock()\n\tdefer b.mutex.Unlock()\n\tresult := generateResponse(req, answer, err)\n\tb.resp = append(b.resp, &result)\n\tb.reqs = b.reqs[1:]\n}\n\n// write response.\nfunc (b *batchCallBuffer) write(ctx RequestContext, isTimeOut bool) {\n\tb.mutex.Lock()\n\tdefer b.mutex.Unlock()\n\tif b.wrote {\n\t\treturn\n\t}\n\tif isTimeOut {\n\t\tfor _, req := range b.reqs {\n\t\t\tresult := generateResponse(req, nil, InternalError(\"request timed out\"))\n\t\t\tb.resp = append(b.resp, &result)\n\t\t}\n\t}\n\tw := ctx.HTTPResponseWriter()\n\tb.wrote = true // can only write once\n\tif len(b.resp) > 0 {\n\t\tWriteBatchResponse(w, b.resp)\n\t}\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/transaction.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"net/http\"\n\t\"strings\"\n)\n\ntype transactionApi struct {\n}\n\nfunc newTransactionApi() *transactionApi {\n\treturn &transactionApi{}\n}\n\ntype sendTxResult struct {\n\tHashes map[string]string `json:\"hashes\"`\n}\n\nfunc txHandlerBatches(r *http.Request, m Mode, mtx map[string][]byte) ([]string, error) {\n\tclient := getClient(r)\n\tlogger := getLogger(r)\n\tvar txData [][]byte\n\tfor _, datum := range mtx {\n\t\ttxData = append(txData, datum)\n\t}\n\tif int64(len(txData)) > syspar.GetMaxTxSize() {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"max_size\": syspar.GetMaxTxSize(), \"size\": len(txData)}).Error(\"transaction size exceeds max size\")\n\t\ttransaction.BadTxForBan(client.KeyID)\n\t\treturn nil, fmt.Errorf(\"the size of tx is too big (%d)\", len(txData))\n\t}\n\n\thash, err := m.ClientTxProcessor.ProcessClientTxBatches(txData, client.KeyID, logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn hash, nil\n}\n\nfunc (t *transactionApi) SendTx(ctx RequestContext, auth Auth, mtx map[string][]byte) (*sendTxResult, *Error) {\n\tr := ctx.HTTPRequest()\n\tclient := getClient(r)\n\n\tif transaction.IsKeyBanned(client.KeyID) {\n\t\treturn nil, DefaultError(fmt.Sprintf(\"The key %d is banned till %s\", client.KeyID, transaction.BannedTill(client.KeyID)))\n\t}\n\tif mtx == nil {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\n\tresult := &sendTxResult{Hashes: make(map[string]string)}\n\n\thash, err := txHandlerBatches(r, auth.Mode, mtx)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\tfor _, key := range hash {\n\t\tresult.Hashes[key] = key\n\t}\n\treturn result, nil\n}\n\ntype txstatusError struct {\n\tType  string `json:\"type,omitempty\"`\n\tError string `json:\"error,omitempty\"`\n\tId    string `json:\"id,omitempty\"`\n}\n\ntype txstatusResult struct {\n\tBlockID string         `json:\"blockid\"`\n\tMessage *txstatusError `json:\"errmsg,omitempty\"`\n\tResult  string         `json:\"result\"`\n\tPenalty int64          `json:\"penalty\"`\n}\n\nfunc getTxStatus(r *http.Request, hash string) (*txstatusResult, error) {\n\tlogger := getLogger(r)\n\n\tvar status txstatusResult\n\tif _, err := hex.DecodeString(hash); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"decoding tx hash from hex\")\n\t\treturn nil, errors.New(\"hash is incorrect\")\n\t}\n\tts := &sqldb.TransactionStatus{}\n\tfound, err := ts.Get([]byte(converter.HexToBin(hash)))\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"getting transaction status by hash\")\n\t\treturn nil, err\n\t}\n\tif !found {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"key\": []byte(converter.HexToBin(hash))}).Debug(\"getting transaction status by hash\")\n\t\treturn nil, errors.New(fmt.Sprintf(\"hash %s has not been found\", hash))\n\t}\n\tcheckErr := func() {\n\t\tif len(ts.Error) > 0 {\n\t\t\tif err := json.Unmarshal([]byte(ts.Error), &status.Message); err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"text\": ts.Error, \"error\": err}).Warn(\"unmarshalling txstatus error\")\n\t\t\t\tstatus.Message = &txstatusError{\n\t\t\t\t\tType:  \"txError\",\n\t\t\t\t\tError: ts.Error,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif ts.BlockID > 0 {\n\t\tstatus.BlockID = converter.Int64ToStr(ts.BlockID)\n\t\tstatus.Penalty = ts.Penalty\n\t\tif ts.Penalty == 1 {\n\t\t\tcheckErr()\n\t\t} else {\n\t\t\tstatus.Result = ts.Error\n\t\t}\n\t} else {\n\t\tcheckErr()\n\t}\n\treturn &status, nil\n}\n\nfunc (t *transactionApi) TxStatus(ctx RequestContext, auth Auth, hashes string) (*map[string]*txstatusResult, *Error) {\n\tresult := map[string]*txstatusResult{}\n\tif hashes == \"\" {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\n\tlist := strings.Split(hashes, \",\")\n\n\tr := ctx.HTTPRequest()\n\n\tfor _, hash := range list {\n\t\tstatus, err := getTxStatus(r, hash)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tresult[hash] = status\n\t}\n\n\treturn &result, nil\n}\n\nfunc (b *transactionApi) TxInfo(hash string, contractInfo *bool) (*TxInfoResult, *Error) {\n\tif hash == \"\" {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\tvar getInfo bool\n\tif contractInfo != nil {\n\t\tgetInfo = *contractInfo\n\t}\n\tstatus, err := getTxInfo(hash, getInfo)\n\tif err != nil {\n\t\treturn nil, DefaultError(err.Error())\n\t}\n\treturn status, nil\n}\n\nfunc (b *transactionApi) TxInfoMultiple(hashList []string, contractInfo *bool) (*MultiTxInfoResult, *Error) {\n\tif hashList == nil {\n\t\treturn nil, InvalidParamsError(paramsEmpty)\n\t}\n\tresult := &MultiTxInfoResult{\n\t\tResults: make(map[string]*TxInfoResult),\n\t}\n\tvar getInfo bool\n\tif contractInfo != nil {\n\t\tgetInfo = *contractInfo\n\t}\n\tfor _, hash := range hashList {\n\t\tstatus, err := getTxInfo(hash, getInfo)\n\t\tif err != nil {\n\t\t\treturn nil, DefaultError(err.Error())\n\t\t}\n\t\tresult.Results[hash] = status\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "packages/service/jsonrpc/txinfo.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage jsonrpc\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"github.com/IBAX-io/go-ibax/packages/block\"\n\t\"github.com/IBAX-io/go-ibax/packages/common\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\n// gas fee info\ntype feeInfo struct {\n\tAmount      string `json:\"amount\"`\n\tTokenSymbol string `json:\"token_symbol\"`\n\tDigits      int    `json:\"digits\"`\n}\n\ntype TxInfoResult struct {\n\tBlockID int64         `json:\"blockid\"`\n\tConfirm int           `json:\"confirm\"`\n\tData    *smart.TxInfo `json:\"data\"`\n}\n\ntype MultiTxInfoResult struct {\n\tResults map[string]*TxInfoResult `json:\"results\"`\n}\n\ntype TxDetailResult struct {\n}\n\nfunc getTxInfo(txHash string, getInfo bool) (*TxInfoResult, error) {\n\tvar status TxInfoResult\n\thash, err := hex.DecodeString(txHash)\n\tif err != nil {\n\t\treturn nil, errors.New(\"hash is incorrect\")\n\t}\n\tltx := &sqldb.LogTransaction{Hash: hash}\n\tfound, err := ltx.GetByHash(nil, hash)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !found {\n\t\treturn &status, nil\n\t}\n\tstatus.BlockID = ltx.Block\n\tvar confirm sqldb.Confirmation\n\tfound, err = confirm.GetConfirmation(ltx.Block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif found {\n\t\tstatus.Confirm = int(confirm.Good)\n\t}\n\tif getInfo {\n\t\tstatus.Data, err = transactionData(ltx.Block, hex.EncodeToString(ltx.Hash))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tstatus.Data.Status = ltx.Status\n\t\tstatus.Data.Ecosystem = ltx.EcosystemID\n\t}\n\treturn &status, nil\n}\n\nfunc transactionData(blockId int64, txHash string) (*smart.TxInfo, error) {\n\tinfo := &smart.TxInfo{}\n\tbk := &sqldb.BlockChain{}\n\tf, err := bk.Get(blockId)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !f {\n\t\treturn nil, errors.New(\"not found\")\n\t}\n\n\tblck, err := block.UnmarshallBlock(bytes.NewBuffer(bk.Data), false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, tx := range blck.Transactions {\n\t\thashStr := hex.EncodeToString(tx.Hash())\n\t\t//find next\n\t\tif hashStr != txHash {\n\t\t\tcontinue\n\t\t}\n\t\tinfo.Address = converter.AddressToString(tx.KeyID())\n\t\tinfo.Hash = hashStr\n\t\tinfo.Size = common.StorageSize(len(tx.Payload())).TerminalString()\n\t\tinfo.CreatedAt = tx.Timestamp()\n\n\t\tif tx.IsSmartContract() {\n\t\t\tinfo.Expedite = tx.SmartContract().TxSmart.Expedite\n\t\t\tif tx.SmartContract().TxContract != nil {\n\t\t\t\tinfo.ContractName = tx.SmartContract().TxContract.Name\n\t\t\t}\n\t\t\tinfo.Params = tx.SmartContract().TxData\n\t\t\tif tx.Type() == types.TransferSelfTxType {\n\t\t\t\tinfo.Params = make(map[string]any)\n\t\t\t\tinfo.Params[\"transferSelf\"] = tx.SmartContract().TxSmart.TransferSelf\n\t\t\t}\n\t\t\tif tx.Type() == types.UtxoTxType {\n\t\t\t\tinfo.Params = make(map[string]any)\n\t\t\t\tinfo.Params[\"utxo\"] = tx.SmartContract().TxSmart.UTXO\n\t\t\t}\n\t\t}\n\t\t//find out break\n\t\tbreak\n\n\t}\n\tinfo.BlockId = blck.Header.BlockId\n\tinfo.BlockHash = hex.EncodeToString(blck.Header.BlockHash)\n\n\treturn info, nil\n}\n"
  },
  {
    "path": "packages/service/node/node_actualization.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage node\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\n// DefaultBlockchainGap is default value for the number of lagging blocks\nconst DefaultBlockchainGap int64 = 10\n\ntype NodeActualizer struct {\n\tavailableBlockchainGap int64\n}\n\nfunc NewNodeActualizer(availableBlockchainGap int64) NodeActualizer {\n\treturn NodeActualizer{\n\t\tavailableBlockchainGap: availableBlockchainGap,\n\t}\n}\n\n// Run is starting node monitoring\nfunc (n *NodeActualizer) Run(ctx context.Context) {\n\tgo func() {\n\t\tlog.Info(\"Node Actualizer monitoring starting\")\n\t\tfor {\n\t\t\tif ctx.Err() != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"error\": ctx.Err(), \"type\": consts.ContextError}).Error(\"context error\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tactual, err := n.checkBlockchainActuality(ctx)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.BCActualizationError, \"err\": err}).Error(\"checking blockchain actuality\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !actual && !IsNodePaused() {\n\t\t\t\tlog.Info(\"Node Actualizer is pausing node activity\")\n\t\t\t\tn.pauseNodeActivity()\n\t\t\t}\n\n\t\t\tif actual && IsNodePaused() {\n\t\t\t\tlog.Info(\"Node Actualizer is resuming node activity\")\n\t\t\t\tn.resumeNodeActivity()\n\t\t\t}\n\n\t\t\ttime.Sleep(time.Second * 5)\n\t\t}\n\t}()\n}\n\nfunc (n *NodeActualizer) checkBlockchainActuality(ctx context.Context) (bool, error) {\n\tcurBlock := &sqldb.InfoBlock{}\n\t_, err := curBlock.Get()\n\tif err != nil {\n\t\treturn false, errors.Wrapf(err, \"retrieving info block\")\n\t}\n\n\tremoteHosts, err := GetNodesBanService().FilterBannedHosts(syspar.GetRemoteHosts())\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t_, maxBlockID, err := tcpclient.HostWithMaxBlock(ctx, remoteHosts)\n\tif err != nil {\n\t\treturn false, errors.Wrapf(err, \"choosing best host\")\n\t}\n\n\t// Currently this node is downloading blockchain\n\tif curBlock.BlockID == 0 || curBlock.BlockID+n.availableBlockchainGap < maxBlockID {\n\t\treturn false, nil\n\t}\n\n\tforeignBlock := &sqldb.BlockChain{}\n\t_, err = foreignBlock.GetMaxForeignBlock(conf.Config.KeyID)\n\tif err != nil {\n\t\treturn false, errors.Wrapf(err, \"retrieving last foreign block\")\n\t}\n\n\t// Node did not accept any blocks for an hour\n\tt := time.Unix(foreignBlock.Time, 0)\n\tif time.Since(t).Minutes() > 30 && len(remoteHosts) > 1 {\n\t\treturn false, nil\n\t}\n\n\treturn true, nil\n}\n\nfunc (n *NodeActualizer) pauseNodeActivity() {\n\tnp.Set(PauseTypeUpdatingBlockchain)\n}\n\nfunc (n *NodeActualizer) resumeNodeActivity() {\n\tnp.Unset()\n}\n"
  },
  {
    "path": "packages/service/node/node_ban.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage node\n\nimport (\n\t\"bytes\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/transaction\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype localBannedNode struct {\n\tHonorNode      *syspar.HonorNode\n\tLocalUnBanTime time.Time\n}\n\ntype NodesBanService struct {\n\tlocalBannedNodes map[int64]localBannedNode\n\thonorNodes       []syspar.HonorNode\n\n\tm *sync.Mutex\n}\n\nvar nbs *NodesBanService\n\n// GetNodesBanService is returning nodes ban service\nfunc GetNodesBanService() *NodesBanService {\n\treturn nbs\n}\n\n// InitNodesBanService initializing nodes ban storage\nfunc InitNodesBanService() error {\n\tnbs = &NodesBanService{\n\t\tlocalBannedNodes: make(map[int64]localBannedNode),\n\t\tm:                &sync.Mutex{},\n\t}\n\n\tnbs.refreshNodes()\n\treturn nil\n}\n\n// RegisterBadBlock is set node to local ban and saving bad block to global registry\nfunc (nbs *NodesBanService) RegisterBadBlock(node syspar.HonorNode, badBlockId, blockTime int64, reason string, register bool) error {\n\tif nbs.IsBanned(node) {\n\t\treturn nil\n\t}\n\n\tnbs.localBan(node)\n\tif !register {\n\t\treturn nil\n\t}\n\terr := nbs.newBadBlock(node, badBlockId, blockTime, reason)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// IsBanned is allows to check node ban (local or global)\nfunc (nbs *NodesBanService) IsBanned(node syspar.HonorNode) bool {\n\tnbs.refreshNodes()\n\n\tnbs.m.Lock()\n\tdefer nbs.m.Unlock()\n\n\tnodeKeyID := crypto.Address(node.PublicKey)\n\t// Searching for local ban\n\tnow := time.Now()\n\n\tif fn, ok := nbs.localBannedNodes[nodeKeyID]; ok {\n\t\tif now.Equal(fn.LocalUnBanTime) || now.After(fn.LocalUnBanTime) {\n\t\t\tdelete(nbs.localBannedNodes, nodeKeyID)\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\t// Searching for global ban.\n\t// Here we don't estimating global ban expiration. If ban time doesn't equal zero - we assuming\n\t// that node is still banned (even if `unban` time has already passed)\n\tfor _, fn := range nbs.honorNodes {\n\t\tif bytes.Equal(fn.PublicKey, node.PublicKey) {\n\t\t\tif !fn.UnbanTime.Equal(time.Unix(0, 0)) {\n\t\t\t\treturn true\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (nbs *NodesBanService) refreshNodes() {\n\tnbs.m.Lock()\n\tnbs.honorNodes = syspar.GetNodes()\n\tnbs.m.Unlock()\n}\n\nfunc (nbs *NodesBanService) localBan(node syspar.HonorNode) {\n\tnbs.m.Lock()\n\tdefer nbs.m.Unlock()\n\n\tts := time.Now().Unix()\n\tte := time.Now().Add(syspar.GetLocalNodeBanTime()).Unix()\n\tif te == ts {\n\t\tte = ts + 120\n\t}\n\tnbs.localBannedNodes[crypto.Address(node.PublicKey)] = localBannedNode{\n\t\tHonorNode:      &node,\n\t\tLocalUnBanTime: time.Unix(te, 0),\n\t\t//LocalUnBanTime: time.Now().Add(syspar.GetLocalNodeBanTime()),\n\t}\n}\n\nfunc (nbs *NodesBanService) newBadBlock(producer syspar.HonorNode, blockId, blockTime int64, reason string) error {\n\tvar currentNode syspar.HonorNode\n\tnbs.m.Lock()\n\tfor _, fn := range nbs.honorNodes {\n\t\tif bytes.Equal(fn.PublicKey, syspar.GetNodePubKey()) {\n\t\t\tcurrentNode = fn\n\t\t\tbreak\n\t\t}\n\t}\n\tnbs.m.Unlock()\n\n\tif len(currentNode.PublicKey) == 0 {\n\t\treturn errors.New(\"cant find current node in honor nodes list\")\n\t}\n\n\tvm := script.GetVM()\n\tcontract := smart.VMGetContract(vm, \"NewBadBlock\", 1)\n\tinfo := contract.Info()\n\n\tsc := types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(info.ID),\n\t\t\tEcosystemID: 1,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tKeyID:       conf.Config.KeyID,\n\t\t},\n\t\tParams: map[string]any{\n\t\t\t\"ProducerNodeID\": crypto.Address(producer.PublicKey),\n\t\t\t\"ConsumerNodeID\": crypto.Address(currentNode.PublicKey),\n\t\t\t\"BlockID\":        blockId,\n\t\t\t\"Timestamp\":      blockTime,\n\t\t\t\"Reason\":         reason,\n\t\t},\n\t}\n\n\tstp := &transaction.SmartTransactionParser{\n\t\tSmartContract: &smart.SmartContract{TxSmart: new(types.SmartTransaction)},\n\t}\n\ttxData, err := stp.BinMarshalWithPrivate(&sc, syspar.GetNodePrivKey(), true)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn transaction.CreateTransaction(txData, stp.Hash, conf.Config.KeyID, stp.Timestamp)\n}\n\nfunc (nbs *NodesBanService) FilterHosts(hosts []string) ([]string, []string, error) {\n\tvar goodHosts, banHosts []string\n\tfor _, h := range hosts {\n\t\tn, err := syspar.GetNodeByHost(h)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"host\": h}).Error(\"getting node by host\")\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif nbs.IsBanned(n) {\n\t\t\tbanHosts = append(banHosts, n.TCPAddress)\n\t\t} else {\n\t\t\tgoodHosts = append(goodHosts, n.TCPAddress)\n\t\t}\n\t}\n\treturn goodHosts, banHosts, nil\n}\n\nfunc (nbs *NodesBanService) FilterBannedHosts(hosts []string) (goodHosts []string, err error) {\n\tgoodHosts, _, err = nbs.FilterHosts(hosts)\n\treturn\n}\n"
  },
  {
    "path": "packages/service/node/node_paused.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage node\n\nimport (\n\t\"sync\"\n)\n\nconst (\n\tNoPause PauseType = 0\n\n\tPauseTypeUpdatingBlockchain PauseType = 1 + iota\n\tPauseTypeStopingNetwork\n)\n\n// np contains the reason why a node should not generating blocks\nvar np = &NodePaused{PauseType: NoPause}\n\ntype PauseType int\n\ntype NodePaused struct {\n\tmutex sync.RWMutex\n\n\tPauseType PauseType\n}\n\nfunc (p PauseType) String() string {\n\tswitch p {\n\tcase NoPause:\n\t\treturn \"node server status is running\"\n\tcase PauseTypeUpdatingBlockchain:\n\t\treturn \"node server is updating\"\n\tcase PauseTypeStopingNetwork:\n\t\treturn \"node server is stopped\"\n\t}\n\treturn \"node server is unknown\"\n}\n\nfunc (np *NodePaused) Set(pt PauseType) {\n\tnp.mutex.Lock()\n\tdefer np.mutex.Unlock()\n\n\tnp.PauseType = pt\n}\n\nfunc (np *NodePaused) Unset() {\n\tnp.mutex.Lock()\n\tdefer np.mutex.Unlock()\n\n\tnp.PauseType = NoPause\n}\n\nfunc (np *NodePaused) Get() PauseType {\n\tnp.mutex.RLock()\n\tdefer np.mutex.RUnlock()\n\n\treturn np.PauseType\n}\n\nfunc (np *NodePaused) IsSet() bool {\n\tnp.mutex.RLock()\n\tdefer np.mutex.RUnlock()\n\n\treturn np.PauseType != NoPause\n}\n\nfunc IsNodePaused() bool {\n\treturn np.IsSet()\n}\n\nfunc PauseNodeActivity(pt PauseType) {\n\tnp.Set(pt)\n}\n\nfunc NodePauseType() PauseType {\n\treturn np.Get()\n}\n"
  },
  {
    "path": "packages/service/node/node_relevance.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage node\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/network/tcpclient\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\nvar updatingEndWhilePaused = make(chan struct{})\n\ntype NodeRelevanceService struct {\n\tavailableBlockchainGap int64\n\tcheckingInterval       time.Duration\n}\n\nfunc NewNodeRelevanceService() *NodeRelevanceService {\n\tvar availableBlockchainGap int64 = consts.AvailableBCGap\n\tif syspar.GetRbBlocks1() > consts.AvailableBCGap {\n\t\tavailableBlockchainGap = syspar.GetRbBlocks1() - consts.AvailableBCGap\n\t}\n\n\tcheckingInterval := syspar.GetMaxBlockTimeDuration() * time.Duration(syspar.GetRbBlocks1()-consts.DefaultNodesConnectDelay)\n\treturn &NodeRelevanceService{\n\t\tavailableBlockchainGap: availableBlockchainGap,\n\t\tcheckingInterval:       checkingInterval,\n\t}\n}\n\n// Run is starting node monitoring\nfunc (n *NodeRelevanceService) Run(ctx context.Context) {\n\tgo func() {\n\t\tlog.Info(\"Node relevance monitoring started\")\n\t\tfor {\n\t\t\trelevance, err := n.checkNodeRelevance(ctx)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.BCRelevanceError, \"err\": err}).Error(\"checking blockchain relevance\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !relevance && !IsNodePaused() {\n\t\t\t\tlog.Info(\"Node Relevance Service is pausing node activity\")\n\t\t\t\tn.pauseNodeActivity()\n\t\t\t}\n\n\t\t\tif relevance && IsNodePaused() {\n\t\t\t\tlog.Info(\"Node Relevance Service is resuming node activity\")\n\t\t\t\tn.resumeNodeActivity()\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-time.After(n.checkingInterval):\n\t\t\tcase <-updatingEndWhilePaused:\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc NodeDoneUpdatingBlockchain() {\n\tif IsNodePaused() {\n\t\tupdatingEndWhilePaused <- struct{}{}\n\t}\n}\n\nfunc (n *NodeRelevanceService) checkNodeRelevance(ctx context.Context) (relevant bool, err error) {\n\tcurBlock := &sqldb.InfoBlock{}\n\t_, err = curBlock.Get()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"err\": err}).Error(\"retrieving info block from db\")\n\t\treturn false, errors.Wrapf(err, \"retrieving info block from db\")\n\t}\n\tvar (\n\t\ttx = &sqldb.Transaction{}\n\t\tr  bool\n\t)\n\tr, err = tx.GetStopNetwork()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"err\": err}).Info(\"retrieving transaction from db\")\n\t\treturn false, nil\n\t}\n\tif r {\n\t\treturn false, nil\n\t}\n\tvar (\n\t\tremoteHosts []string\n\t)\n\tif syspar.IsHonorNodeMode() {\n\t\tremoteHosts, err = GetNodesBanService().FilterBannedHosts(syspar.GetRemoteHosts())\n\t} else {\n\t\tcandidateNodes, err := sqldb.GetCandidateNode(syspar.SysInt(syspar.NumberNodes))\n\t\tif err == nil && len(candidateNodes) > 0 {\n\t\t\tfor _, node := range candidateNodes {\n\t\t\t\tremoteHosts = append(remoteHosts, node.TcpAddress)\n\t\t\t}\n\t\t}\n\t}\n\n\tif err != nil {\n\t\treturn false, err\n\t}\n\t// Node is single in blockchain network and it can't be irrelevant\n\tif len(remoteHosts) == 0 {\n\t\treturn true, nil\n\t}\n\n\t_, maxBlockID, err := tcpclient.HostWithMaxBlock(ctx, remoteHosts)\n\tif err != nil {\n\t\tif err == tcpclient.ErrNodesUnavailable {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn false, errors.Wrapf(err, \"choosing best host\")\n\t}\n\n\t// Node can't connect to others\n\tif maxBlockID == -1 {\n\t\tlog.WithFields(log.Fields{\"hosts\": remoteHosts}).Info(\"can't connect to others, stopping node relevance\")\n\t\treturn false, nil\n\t}\n\n\t// Node blockchain is stale\n\tif curBlock.BlockID+n.availableBlockchainGap < maxBlockID {\n\t\tlog.WithFields(log.Fields{\"maxBlockID\": maxBlockID, \"curBlockID\": curBlock.BlockID, \"Gap\": n.availableBlockchainGap}).Info(\"blockchain is stale, stopping node relevance\")\n\t\treturn false, nil\n\t}\n\n\treturn true, nil\n}\n\nfunc (n *NodeRelevanceService) pauseNodeActivity() {\n\tnp.Set(PauseTypeUpdatingBlockchain)\n}\n\nfunc (n *NodeRelevanceService) resumeNodeActivity() {\n\tnp.Unset()\n}\n"
  },
  {
    "path": "packages/service/protos/build.sh",
    "content": "#!/bin/bash\n\n# install protoc 3.7.1\n# export GO111MODULES=on\n# go install google.golang.org/protobuf/cmd/protoc-gen-go@latest\n# go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest\n\nprotoc -I ./ ./*.proto \\\n    -I ./googleapis \\\n    --go_out ./gengo/ --go_opt paths=source_relative \\\n    --go-grpc_out ./gengo/ --go-grpc_opt paths=source_relative \\\n    --grpc-gateway_out ./gengo/ --grpc-gateway_opt paths=source_relative\n\n"
  },
  {
    "path": "packages/service/protos/googleapis/google/api/annotations.proto",
    "content": "// Copyright 2015 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\nimport \"google/api/http.proto\";\nimport \"google/protobuf/descriptor.proto\";\n\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"AnnotationsProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\nextend google.protobuf.MethodOptions {\n  // See `HttpRule`.\n  HttpRule http = 72295728;\n}"
  },
  {
    "path": "packages/service/protos/googleapis/google/api/http.proto",
    "content": "// Copyright 2015 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/annotations;annotations\";\noption java_multiple_files = true;\noption java_outer_classname = \"HttpProto\";\noption java_package = \"com.google.api\";\noption objc_class_prefix = \"GAPI\";\n\n// Defines the HTTP configuration for an API service. It contains a list of\n// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method\n// to one or more HTTP REST API methods.\nmessage Http {\n  // A list of HTTP configuration rules that apply to individual API methods.\n  //\n  // **NOTE:** All service configuration rules follow \"last one wins\" order.\n  repeated HttpRule rules = 1;\n\n  // When set to true, URL path parameters will be fully URI-decoded except in\n  // cases of single segment matches in reserved expansion, where \"%2F\" will be\n  // left encoded.\n  //\n  // The default behavior is to not decode RFC 6570 reserved characters in multi\n  // segment matches.\n  bool              fully_decode_reserved_expansion = 2;\n}\n\n// # gRPC Transcoding\n//\n// gRPC Transcoding is a feature for mapping between a gRPC method and one or\n// more HTTP REST endpoints. It allows developers to build a single API service\n// that supports both gRPC APIs and REST APIs. Many systems, including [Google\n// APIs](https://github.com/googleapis/googleapis),\n// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC\n// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),\n// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature\n// and use it for large scale production services.\n//\n// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies\n// how different portions of the gRPC request message are mapped to the URL\n// path, URL query parameters, and HTTP request body. It also controls how the\n// gRPC response message is mapped to the HTTP response body. `HttpRule` is\n// typically specified as an `google.api.http` annotation on the gRPC method.\n//\n// Each mapping specifies a URL path template and an HTTP method. The path\n// template may refer to one or more fields in the gRPC request message, as long\n// as each field is a non-repeated field with a primitive (non-message) type.\n// The path template controls how fields of the request message are mapped to\n// the URL path.\n//\n// Example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//             get: \"/v1/{name=messages/*}\"\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       string name = 1; // Mapped to URL path.\n//     }\n//     message Message {\n//       string text = 1; // The resource content.\n//     }\n//\n// This enables an HTTP REST to gRPC mapping as below:\n//\n// HTTP | gRPC\n// -----|-----\n// `GET /v1/messages/123456`  | `GetMessage(name: \"messages/123456\")`\n//\n// Any fields in the request message which are not bound by the path template\n// automatically become HTTP query parameters if there is no HTTP request body.\n// For example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//             get:\"/v1/messages/{message_id}\"\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       message SubMessage {\n//         string subfield = 1;\n//       }\n//       string message_id = 1; // Mapped to URL path.\n//       int64 revision = 2;    // Mapped to URL query parameter `revision`.\n//       SubMessage sub = 3;    // Mapped to URL query parameter `sub.subfield`.\n//     }\n//\n// This enables a HTTP JSON to RPC mapping as below:\n//\n// HTTP | gRPC\n// -----|-----\n// `GET /v1/messages/123456?revision=2&sub.subfield=foo` |\n// `GetMessage(message_id: \"123456\" revision: 2 sub: SubMessage(subfield:\n// \"foo\"))`\n//\n// Note that fields which are mapped to URL query parameters must have a\n// primitive type or a repeated primitive type or a non-repeated message type.\n// In the case of a repeated type, the parameter can be repeated in the URL\n// as `...?param=A&param=B`. In the case of a message type, each field of the\n// message is mapped to a separate parameter, such as\n// `...?foo.a=A&foo.b=B&foo.c=C`.\n//\n// For HTTP methods that allow a request body, the `body` field\n// specifies the mapping. Consider a REST update method on the\n// message resource collection:\n//\n//     service Messaging {\n//       rpc UpdateMessage(UpdateMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//           patch: \"/v1/messages/{message_id}\"\n//           body: \"message\"\n//         };\n//       }\n//     }\n//     message UpdateMessageRequest {\n//       string message_id = 1; // mapped to the URL\n//       Message message = 2;   // mapped to the body\n//     }\n//\n// The following HTTP JSON to RPC mapping is enabled, where the\n// representation of the JSON in the request body is determined by\n// protos JSON encoding:\n//\n// HTTP | gRPC\n// -----|-----\n// `PATCH /v1/messages/123456 { \"text\": \"Hi!\" }` | `UpdateMessage(message_id:\n// \"123456\" message { text: \"Hi!\" })`\n//\n// The special name `*` can be used in the body mapping to define that\n// every field not bound by the path template should be mapped to the\n// request body.  This enables the following alternative definition of\n// the update method:\n//\n//     service Messaging {\n//       rpc UpdateMessage(Message) returns (Message) {\n//         option (google.api.http) = {\n//           patch: \"/v1/messages/{message_id}\"\n//           body: \"*\"\n//         };\n//       }\n//     }\n//     message Message {\n//       string message_id = 1;\n//       string text = 2;\n//     }\n//\n//\n// The following HTTP JSON to RPC mapping is enabled:\n//\n// HTTP | gRPC\n// -----|-----\n// `PATCH /v1/messages/123456 { \"text\": \"Hi!\" }` | `UpdateMessage(message_id:\n// \"123456\" text: \"Hi!\")`\n//\n// Note that when using `*` in the body mapping, it is not possible to\n// have HTTP parameters, as all fields not bound by the path end in\n// the body. This makes this option more rarely used in practice when\n// defining REST APIs. The common usage of `*` is in custom methods\n// which don't use the URL at all for transferring data.\n//\n// It is possible to define multiple HTTP methods for one RPC by using\n// the `additional_bindings` option. Example:\n//\n//     service Messaging {\n//       rpc GetMessage(GetMessageRequest) returns (Message) {\n//         option (google.api.http) = {\n//           get: \"/v1/messages/{message_id}\"\n//           additional_bindings {\n//             get: \"/v1/users/{user_id}/messages/{message_id}\"\n//           }\n//         };\n//       }\n//     }\n//     message GetMessageRequest {\n//       string message_id = 1;\n//       string user_id = 2;\n//     }\n//\n// This enables the following two alternative HTTP JSON to RPC mappings:\n//\n// HTTP | gRPC\n// -----|-----\n// `GET /v1/messages/123456` | `GetMessage(message_id: \"123456\")`\n// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: \"me\" message_id:\n// \"123456\")`\n//\n// ## Rules for HTTP mapping\n//\n// 1. Leaf request fields (recursive expansion nested messages in the request\n//    message) are classified into three categories:\n//    - Fields referred by the path template. They are passed via the URL path.\n//    - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP\n//      request body.\n//    - All other fields are passed via the URL query parameters, and the\n//      parameter name is the field path in the request message. A repeated\n//      field can be represented as multiple query parameters under the same\n//      name.\n//  2. If [HttpRule.body][google.api.HttpRule.body] is \"*\", there is no URL query parameter, all fields\n//     are passed via URL path and HTTP request body.\n//  3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all\n//     fields are passed via URL path and URL query parameters.\n//\n// ### Path template syntax\n//\n//     Template = \"/\" Segments [ Verb ] ;\n//     Segments = Segment { \"/\" Segment } ;\n//     Segment  = \"*\" | \"**\" | LITERAL | Variable ;\n//     Variable = \"{\" FieldPath [ \"=\" Segments ] \"}\" ;\n//     FieldPath = IDENT { \".\" IDENT } ;\n//     Verb     = \":\" LITERAL ;\n//\n// The syntax `*` matches a single URL path segment. The syntax `**` matches\n// zero or more URL path segments, which must be the last part of the URL path\n// except the `Verb`.\n//\n// The syntax `Variable` matches part of the URL path as specified by its\n// template. A variable template must not contain other variables. If a variable\n// matches a single path segment, its template may be omitted, e.g. `{var}`\n// is equivalent to `{var=*}`.\n//\n// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`\n// contains any reserved character, such characters should be percent-encoded\n// before the matching.\n//\n// If a variable contains exactly one path segment, such as `\"{var}\"` or\n// `\"{var=*}\"`, when such a variable is expanded into a URL path on the client\n// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The\n// server side does the reverse decoding. Such variables show up in the\n// [Discovery\n// Document](https://developers.google.com/discovery/v1/reference/apis) as\n// `{var}`.\n//\n// If a variable contains multiple path segments, such as `\"{var=foo/*}\"`\n// or `\"{var=**}\"`, when such a variable is expanded into a URL path on the\n// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.\n// The server side does the reverse decoding, except \"%2F\" and \"%2f\" are left\n// unchanged. Such variables show up in the\n// [Discovery\n// Document](https://developers.google.com/discovery/v1/reference/apis) as\n// `{+var}`.\n//\n// ## Using gRPC API Service Configuration\n//\n// gRPC API Service Configuration (service config) is a configuration language\n// for configuring a gRPC service to become a user-facing product. The\n// service config is simply the YAML representation of the `google.api.Service`\n// proto message.\n//\n// As an alternative to annotating your proto file, you can configure gRPC\n// transcoding in your service config YAML files. You do this by specifying a\n// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same\n// effect as the proto annotation. This can be particularly useful if you\n// have a proto that is reused in multiple services. Note that any transcoding\n// specified in the service config will override any matching transcoding\n// configuration in the proto.\n//\n// Example:\n//\n//     http:\n//       rules:\n//         # Selects a gRPC method and applies HttpRule to it.\n//         - selector: example.v1.Messaging.GetMessage\n//           get: /v1/messages/{message_id}/{sub.subfield}\n//\n// ## Special notes\n//\n// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the\n// proto to JSON conversion must follow the [proto3\n// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).\n//\n// While the single segment variable follows the semantics of\n// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String\n// Expansion, the multi segment variable **does not** follow RFC 6570 Section\n// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion\n// does not expand special characters like `?` and `#`, which would lead\n// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding\n// for multi segment variables.\n//\n// The path variables **must not** refer to any repeated or mapped field,\n// because client libraries are not capable of handling such variable expansion.\n//\n// The path variables **must not** capture the leading \"/\" character. The reason\n// is that the most common use case \"{var}\" does not capture the leading \"/\"\n// character. For consistency, all path variables must share the same behavior.\n//\n// Repeated message fields must not be mapped to URL query parameters, because\n// no client library can support such complicated mapping.\n//\n// If an API needs to use a JSON array for request or response body, it can map\n// the request or response body to a repeated field. However, some gRPC\n// Transcoding implementations may not support this feature.\nmessage HttpRule {\n  // Selects a method to which this rule applies.\n  //\n  // Refer to [selector][google.api.DocumentationRule.selector] for syntax details.\n  string            selector = 1;\n\n  // Determines the URL pattern is matched by this rules. This pattern can be\n  // used with any of the {get|put|post|delete|patch} methods. A custom method\n  // can be defined using the 'custom' field.\n  oneof pattern {\n    // Maps to HTTP GET. Used for listing and getting information about\n    // resources.\n    string            get = 2;\n\n    // Maps to HTTP PUT. Used for replacing a resource.\n    string            put = 3;\n\n    // Maps to HTTP POST. Used for creating a resource or performing an action.\n    string            post = 4;\n\n    // Maps to HTTP DELETE. Used for deleting a resource.\n    string            delete = 5;\n\n    // Maps to HTTP PATCH. Used for updating a resource.\n    string            patch = 6;\n\n    // The custom pattern is used for specifying an HTTP method that is not\n    // included in the `pattern` field, such as HEAD, or \"*\" to leave the\n    // HTTP method unspecified for this rule. The wild-card rule is useful\n    // for services that provide content to Web (HTML) clients.\n    CustomHttpPattern custom = 8;\n  }\n\n  // The name of the request field whose value is mapped to the HTTP request\n  // body, or `*` for mapping all request fields not captured by the path\n  // pattern to the HTTP body, or omitted for not having any HTTP request body.\n  //\n  // NOTE: the referred field must be present at the top-level of the request\n  // message type.\n  string            body = 7;\n\n  // Optional. The name of the response field whose value is mapped to the HTTP\n  // response body. When omitted, the entire response message will be used\n  // as the HTTP response body.\n  //\n  // NOTE: The referred field must be present at the top-level of the response\n  // message type.\n  string            response_body = 12;\n\n  // Additional HTTP bindings for the selector. Nested bindings must\n  // not contain an `additional_bindings` field themselves (that is,\n  // the nesting may only be one level deep).\n  repeated HttpRule additional_bindings = 11;\n}\n\n// A custom pattern is used for defining custom HTTP verb.\nmessage CustomHttpPattern {\n  // The name of this custom HTTP verb.\n  string kind = 1;\n\n  // The path matched by this custom verb.\n  string path = 2;\n}"
  },
  {
    "path": "packages/smart/builtin_excel.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\txl \"github.com/360EntSecGroup-Skylar/excelize\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// GetDataFromXLSX returns json by parameters range\nfunc GetDataFromXLSX(sc *SmartContract, binaryID, startLine, linesCount, sheetNum int64) (data []any, err error) {\n\tbook, err := excelBookFromStoredBinary(sc, binaryID)\n\tif err != nil || book == nil {\n\t\treturn nil, err\n\t}\n\n\tsheetName := book.GetSheetName(int(sheetNum))\n\trows := book.GetRows(sheetName)\n\tendLine := startLine + linesCount\n\tif endLine > int64(len(rows)) {\n\t\tendLine = int64(len(rows))\n\t}\n\tprocessedRows := []any{}\n\tfor ; startLine < endLine; startLine++ {\n\t\tvar row []any\n\t\tfor _, item := range rows[startLine] {\n\t\t\trow = append(row, item)\n\t\t}\n\t\tprocessedRows = append(processedRows, row)\n\t}\n\treturn processedRows, nil\n}\n\n// GetRowsCountXLSX returns count of rows from excel file\nfunc GetRowsCountXLSX(sc *SmartContract, binaryID, sheetNum int64) (int64, error) {\n\tbook, err := excelBookFromStoredBinary(sc, binaryID)\n\tif err != nil {\n\t\treturn -1, err\n\t}\n\n\tsheetName := book.GetSheetName(int(sheetNum))\n\trows := book.GetRows(sheetName)\n\treturn int64(len(rows)), nil\n}\n\nfunc excelBookFromStoredBinary(sc *SmartContract, binaryID int64) (*xl.File, error) {\n\tbin := &sqldb.Binary{}\n\tbin.SetTablePrefix(converter.Int64ToStr(sc.TxSmart.EcosystemID))\n\tfound, err := bin.GetByID(binaryID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"binary_id\": binaryID}).Error(\"binary_id not found\")\n\t\treturn nil, nil\n\t}\n\n\treturn xl.OpenReader(bytes.NewReader(bin.Data))\n}\n"
  },
  {
    "path": "packages/smart/contract.go",
    "content": "package smart\n\nimport (\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\n// Contract contains the information about the contract.\ntype Contract struct {\n\tName          string\n\tCalled        uint32\n\tFreeRequest   bool\n\tTxGovAccount  int64   // state wallet\n\tRate          float64 // money rate\n\tTableAccounts string\n\tStackCont     []any // Stack of called contracts\n\tExtend        map[string]any\n\tBlock         *script.CodeBlock\n}\n\nfunc (c *Contract) Info() *script.ContractInfo {\n\treturn c.Block.GetContractInfo()\n}\n\n// LoadContracts reads and compiles contracts from smart_contracts tables\nfunc LoadContracts() error {\n\tcontract := &sqldb.Contract{}\n\tcount, err := contract.Count(nil)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"getting count of contracts\")\n\t}\n\n\tdefer script.GetVM().FlushExtern()\n\tvar offset int\n\tlistCount := consts.ContractList\n\tfor ; int64(offset) < count; offset += listCount {\n\t\tlist, err := contract.GetList(offset, listCount)\n\t\tif err != nil {\n\t\t\treturn logErrorDB(err, \"getting list of contracts\")\n\t\t}\n\t\tif err = loadContractList(list); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// LoadContract reads and compiles contract of new state\nfunc LoadContract(transaction *sqldb.DbTransaction, ecosystem int64) (err error) {\n\n\tcontract := &sqldb.Contract{}\n\n\tdefer script.GetVM().FlushExtern()\n\tlist, err := contract.GetFromEcosystem(transaction, ecosystem)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"selecting all contracts from ecosystem\")\n\t}\n\tif err = loadContractList(list); err != nil {\n\t\treturn err\n\t}\n\treturn\n}\n\nfunc VMGetContract(vm *script.VM, name string, state uint32) *Contract {\n\tif len(name) == 0 {\n\t\treturn nil\n\t}\n\tname = script.StateName(state, name)\n\tobj, ok := vm.Objects[name]\n\n\tif ok && obj.Type == script.ObjectType_Contract {\n\t\treturn &Contract{Name: name, Block: obj.GetCodeBlock()}\n\t}\n\treturn nil\n}\n\nfunc VMGetContractByID(vm *script.VM, id int32) *Contract {\n\tvar tableID int64\n\tif id > consts.ShiftContractID {\n\t\ttableID = int64(id - consts.ShiftContractID)\n\t\tid = int32(tableID + vm.ShiftContract)\n\t}\n\tidcont := id\n\tif len(vm.Children) <= int(idcont) {\n\t\treturn nil\n\t}\n\tif vm.Children[idcont] == nil || vm.Children[idcont].Type != script.ObjectType_Contract {\n\t\treturn nil\n\t}\n\tif tableID > 0 && vm.Children[idcont].GetContractInfo().Owner.TableID != tableID {\n\t\treturn nil\n\t}\n\treturn &Contract{Name: vm.Children[idcont].GetContractInfo().Name,\n\t\tBlock: vm.Children[idcont]}\n}\n\n// GetContract returns true if the contract exists in smartVM\nfunc GetContract(name string, state uint32) *Contract {\n\treturn VMGetContract(script.GetVM(), name, state)\n}\n\n// GetUsedContracts returns the list of contracts which are called from the specified contract\nfunc GetUsedContracts(name string, state uint32, full bool) []string {\n\treturn vmGetUsedContracts(script.GetVM(), name, state, full)\n}\n\n// GetContractByID returns true if the contract exists\nfunc GetContractByID(id int32) *Contract {\n\treturn VMGetContractByID(script.GetVM(), id)\n}\n\n// GetFunc returns the block of the specified function in the contract\nfunc (contract *Contract) GetFunc(name string) *script.CodeBlock {\n\tif block, ok := (*contract).Block.Objects[name]; ok && block.Type == script.ObjectType_Func {\n\t\treturn block.GetCodeBlock()\n\t}\n\treturn nil\n}\n\nfunc loadContractList(list []sqldb.Contract) error {\n\tif script.GetVM().ShiftContract == 0 {\n\t\tscript.LoadSysFuncs(script.GetVM(), 1)\n\t\tscript.GetVM().ShiftContract = int64(len(script.GetVM().Children) - 1)\n\t}\n\n\tfor _, item := range list {\n\t\tclist, err := script.ContractsList(item.Value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\towner := script.OwnerInfo{\n\t\t\tStateID:  uint32(item.EcosystemID),\n\t\t\tActive:   false,\n\t\t\tTableID:  item.ID,\n\t\t\tWalletID: item.WalletID,\n\t\t\tTokenID:  item.TokenID,\n\t\t}\n\t\tif err = script.GetVM().Compile([]rune(item.Value), &owner); err != nil {\n\t\t\tlogErrorValue(err, consts.EvalError, \"Load Contract\", strings.Join(clist, `,`))\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc vmGetUsedContracts(vm *script.VM, name string, state uint32, full bool) []string {\n\tcontract := VMGetContract(vm, name, state)\n\tif contract == nil || contract.Info().Used == nil {\n\t\treturn nil\n\t}\n\tret := make([]string, 0)\n\tused := make(map[string]bool)\n\tfor key := range contract.Info().Used {\n\t\tret = append(ret, key)\n\t\tused[key] = true\n\t\tif full {\n\t\t\tsub := vmGetUsedContracts(vm, key, state, full)\n\t\t\tfor _, item := range sub {\n\t\t\t\tif _, ok := used[item]; !ok {\n\t\t\t\t\tret = append(ret, item)\n\t\t\t\t\tused[item] = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn ret\n}\n"
  },
  {
    "path": "packages/smart/datetime.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n)\n\nconst (\n\tdateTimeFormat = \"2006-01-02 15:04:05\"\n)\n\n// Date formats timestamp to specified date format\nfunc Date(timeFormat string, timestamp int64) string {\n\tt := time.Unix(timestamp, 0)\n\treturn t.Format(timeFormat)\n}\n\nfunc BlockTime(sc *SmartContract) string {\n\tvar blockTime int64\n\tif sc.BlockHeader != nil {\n\t\tblockTime = sc.BlockHeader.Timestamp\n\t}\n\tif sc.CLB {\n\t\tblockTime = time.Now().Unix()\n\t}\n\treturn Date(dateTimeFormat, blockTime)\n}\n\nfunc DateTime(unix int64) string {\n\treturn Date(dateTimeFormat, unix)\n}\n\nfunc DateTimeLocation(unix int64, locationName string) (string, error) {\n\tloc, err := time.LoadLocation(locationName)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"Load location\")\n\t}\n\n\treturn time.Unix(unix, 0).In(loc).Format(dateTimeFormat), nil\n}\nfunc AddDate(unix, years, months, days int64) int64 {\n\treturn time.Unix(unix, 0).AddDate(int(years), int(months), int(days)).Unix()\n}\n\nfunc UnixDateTime(value string) int64 {\n\tt, err := time.Parse(dateTimeFormat, value)\n\tif err != nil {\n\t\treturn 0\n\t}\n\treturn t.Unix()\n}\n\nfunc UnixDateTimeLocation(value, locationName string) (int64, error) {\n\tloc, err := time.LoadLocation(locationName)\n\tif err != nil {\n\t\treturn 0, errors.Wrap(err, \"Load location\")\n\t}\n\n\tt, err := time.ParseInLocation(dateTimeFormat, value, loc)\n\tif err != nil {\n\t\treturn 0, errors.Wrap(err, \"Parse time\")\n\t}\n\n\treturn t.Unix(), nil\n}\n"
  },
  {
    "path": "packages/smart/errors.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nconst (\n\teContractLoop          = `there is loop in %s contract`\n\teContractExist         = `contract %s already exists`\n\teLatin                 = `Name %s must only contain latin, digit and '_', '-' characters`\n\teAccessContract        = `%s can only be called with condition: %s`\n\teColumnExist           = `column %s exists`\n\teColumnNotExist        = `column %s doesn't exist`\n\teColumnType            = `Type '%s' of columns is not supported`\n\teNotCustomTable        = `%s is not a custom table`\n\teEmptyCond             = `%v condition is empty`\n\teIncorrectSignature    = `incorrect signature %s`\n\teItemNotFound          = `item %d has not been found`\n\teManyColumns           = `Too many columns. Limit is %d`\n\teNotCondition          = `There is not %s in parameters`\n\teParamNotFound         = `Parameter %s has not been found`\n\teRecordNotFound        = `Record %s has not been found`\n\teTableExists           = `table %s exists`\n\teTableNotFound         = `table %s has not been found`\n\teTypeJSON              = `Type %T doesn't support json marshalling`\n\teUnknownContract       = `Unknown contract %s`\n\teUnsupportedType       = \"Unsupported type %T\"\n\teWrongRandom           = `wrong random parameters min: %v, max: %v`\n\teGreaterThan           = `%s must be greater than 0`\n\teTableNotEmpty         = `Table %s is not empty`\n\teColumnNotDeleted      = `Column %s cannot be deleted`\n\teRollbackContract      = `Wrong rollback of the latest contract %d != %d`\n\teExternalNet           = `External network %s is not defined`\n\teKeyNotFound           = `sender %s has not been found`\n\teEcoKeyNotFound        = `sender %s has not been found in ecosystem %d`\n\teEcoKeyDisable         = `%s disable in ecosystem %d`\n\teEcoFuelRate           = `fuel rate must be greater than 0 or empty in ecosystem %d`\n\teEcoCurrentBalance     = `account %s current balance is not enough in ecosystem %d`\n\teEcoCurrentBalanceDiff = eEcoCurrentBalance + `, at least [%s] difference`\n)\n\nvar (\n\terrDelayedContract   = errors.New(`incorrect delayed contract`)\n\terrAccessDenied      = errors.New(`access denied`)\n\terrConditionEmpty    = errors.New(`conditions is empty`)\n\terrContractNotFound  = errors.New(`contract has not been found`)\n\terrTaxes             = errors.New(\"not enough money to pay the taxes fee\")\n\terrEmptyColumn       = errors.New(`column name is empty`)\n\terrWrongColumn       = errors.New(`column name cannot begin with digit`)\n\terrNotFound          = errors.New(`record has not been found`)\n\terrContractChange    = errors.New(`contract cannot be removed or inserted`)\n\terrDeletedKey        = errors.New(`the key is deleted`)\n\terrDiffKeys          = errors.New(`contract and user public keys are different`)\n\terrEmpty             = errors.New(`empty value and condition`)\n\terrEmptyCond         = errors.New(`the condition is empty`)\n\terrEmptyContract     = errors.New(`empty contract name in ContractConditions`)\n\terrEmptyPublicKey    = errors.New(`empty public key`)\n\terrFounderAccount    = errors.New(`unknown founder account`)\n\terrKeyIDAccount      = errors.New(`unknown address account`)\n\terrFuelRate          = errors.New(`fuel rate must be greater than 0`)\n\terrIncorrectSign     = errors.New(`incorrect sign`)\n\terrIncorrectType     = errors.New(`incorrect type`)\n\terrInvalidValue      = errors.New(`invalid value`)\n\terrNameChange        = errors.New(`contracts or functions names cannot be changed`)\n\terrNegPrice          = errors.New(`price value is negative`)\n\terrOneContract       = errors.New(`only one contract must be in the record`)\n\terrPermEmpty         = errors.New(`permissions are empty`)\n\terrRecursion         = errors.New(\"recursion detected\")\n\terrSameColumns       = errors.New(`there are the same columns`)\n\terrTableName         = errors.New(`the name of the table cannot begin with @`)\n\terrTableEmptyName    = errors.New(`the table name cannot be empty`)\n\terrUndefColumns      = errors.New(`columns are undefined`)\n\terrUpdNotExistRecord = errors.New(`update for not existing record`)\n\terrWrongSignature    = errors.New(`wrong signature`)\n\terrParseTransaction  = errors.New(`parse transaction`)\n\terrWhereUpdate       = errors.New(`there is not Where in Update request`)\n\terrNotValidUTF       = errors.New(`result is not valid utf-8 string`)\n\terrFloat             = errors.New(`incorrect float value`)\n\terrFloatResult       = errors.New(`incorrect float result`)\n\n\terrMaxPrice = fmt.Errorf(`price value is more than %d`, MaxPrice)\n)\n"
  },
  {
    "path": "packages/smart/funcs.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"bytes\"\n\t\"database/sql\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode/utf8\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/clbmanager\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/base58\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/hashalgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/scheduler\"\n\t\"github.com/IBAX-io/go-ibax/packages/scheduler/contract\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/btcsuite/btcd/btcec/v2\"\n\t\"github.com/btcsuite/btcd/btcec/v2/schnorr\"\n\t\"github.com/btcsuite/btcd/btcutil\"\n\t\"github.com/btcsuite/btcd/chaincfg\"\n\t\"github.com/btcsuite/btcd/txscript\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"golang.org/x/crypto/sha3\"\n)\n\nconst (\n\tnodeBanNotificationHeader = \"Your node was banned\"\n\thistoryLimit              = 250\n\tcontractTxType            = 128\n)\n\nvar (\n\tErrNotImplementedOnCLB = errors.New(\"Contract not implemented on CLB\")\n)\n\nvar BOM = []byte{0xEF, 0xBB, 0xBF}\n\ntype permTable struct {\n\tInsert    string `json:\"insert\"`\n\tUpdate    string `json:\"update\"`\n\tNewColumn string `json:\"new_column\"`\n\tRead      string `json:\"read,omitempty\"`\n\tFilter    string `json:\"filter,omitempty\"`\n}\n\ntype permColumn struct {\n\tUpdate string `json:\"update\"`\n\tRead   string `json:\"read,omitempty\"`\n}\n\ntype TxInfo struct {\n\tBlockId      int64          `json:\"block_id\"`\n\tBlockHash    string         `json:\"block_hash\"`\n\tAddress      string         `json:\"address\"`\n\tEcosystem    int64          `json:\"ecosystem\"`\n\tHash         string         `json:\"hash\"`\n\tExpedite     string         `json:\"expedite\"`\n\tContractName string         `json:\"contract_name\"`\n\tParams       map[string]any `json:\"params\"`\n\tCreatedAt    int64          `json:\"created_at\"`\n\tSize         string         `json:\"size\"`\n\tStatus       int64          `json:\"status\"` //0:success 1:penalty\n}\n\ntype TableInfo struct {\n\tColumns map[string]string\n\tTable   *sqldb.Table\n}\n\ntype FlushInfo struct {\n\tID   uint32            // id\n\tPrev *script.CodeBlock // previous item, nil if the new item has been appended\n\tInfo *script.ObjInfo\n\tName string // the name\n}\n\nfunc (finfo *FlushInfo) FlushVM() {\n\tif finfo.Prev == nil {\n\t\tif finfo.ID != uint32(len(script.GetVM().Children)-1) {\n\t\t\t//logger.WithFields(log.Fields{\"type\": consts.ContractError, \"value\": finfo.ID, \"len\": len(GetVM().Children) - 1}).Error(\"flush rollback\")\n\t\t} else {\n\t\t\tscript.GetVM().Children = script.GetVM().Children[:len(script.GetVM().Children)-1]\n\t\t\tdelete(script.GetVM().Objects, finfo.Name)\n\t\t}\n\t} else {\n\t\tscript.GetVM().Children[finfo.ID] = finfo.Prev\n\t\tscript.GetVM().Objects[finfo.Name] = finfo.Info\n\t}\n}\n\n// NotifyInfo is used for sending delayed notifications\ntype NotifyInfo struct {\n\tRoles       bool // if true then UpdateRolesNotifications, otherwise UpdateNotifications\n\tEcosystemID int64\n\tList        []string\n}\n\nvar (\n\tfuncCallsDBP = map[string]struct{}{\n\t\t\"DBInsert\":              {},\n\t\t\"DBUpdate\":              {},\n\t\t\"DBUpdatePlatformParam\": {},\n\t\t\"DBUpdateExt\":           {},\n\t\t\"DBSelect\":              {},\n\t}\n\twriteFuncs = map[string]struct{}{\n\t\t\"CreateColumn\":          {},\n\t\t\"CreateTable\":           {},\n\t\t\"DBInsert\":              {},\n\t\t\"DBUpdate\":              {},\n\t\t\"DBUpdatePlatformParam\": {},\n\t\t\"DBUpdateExt\":           {},\n\t\t\"CreateEcosystem\":       {},\n\t\t\"CreateContract\":        {},\n\t\t\"UpdateContract\":        {},\n\t\t\"CreateLanguage\":        {},\n\t\t\"EditLanguage\":          {},\n\t\t\"BindWallet\":            {},\n\t\t\"UnbindWallet\":          {},\n\t\t\"EditEcosysName\":        {},\n\t\t\"UpdateNodesBan\":        {},\n\t\t\"UpdateCron\":            {},\n\t\t\"CreateCLB\":             {},\n\t\t\"DeleteCLB\":             {},\n\t\t\"DelColumn\":             {},\n\t\t\"DelTable\":              {},\n\t}\n\t// map for table name to parameter with conditions\n\ttableParamConditions = map[string]string{\n\t\t\"pages\":      \"changing_page\",\n\t\t\"menu\":       \"changing_menu\",\n\t\t\"contracts\":  \"changing_contracts\",\n\t\t\"snippets\":   \"changing_snippets\",\n\t\t\"languages\":  \"changing_language\",\n\t\t\"tables\":     \"changing_tables\",\n\t\t\"parameters\": \"changing_parameters\",\n\t\t\"app_params\": \"changing_app_params\",\n\t}\n\ttypeToPSQL = map[string]string{\n\t\t`json`:      `jsonb`,\n\t\t`varchar`:   `varchar(102400)`,\n\t\t`character`: `character(1) NOT NULL DEFAULT '0'`,\n\t\t`number`:    `bigint NOT NULL DEFAULT '0'`,\n\t\t`datetime`:  `timestamp`,\n\t\t`double`:    `double precision`,\n\t\t`money`:     `decimal (30, 0) NOT NULL DEFAULT '0'`,\n\t\t`text`:      `text`,\n\t\t`bytea`:     `bytea NOT NULL DEFAULT '\\x'`,\n\t}\n)\n\n// EmbedFuncs is extending vm with embedded functions\nfunc EmbedFuncs(vt script.VMType) map[string]any {\n\tf := map[string]any{\n\t\t\"AddressToId\":                  converter.AddressToID,\n\t\t\"ColumnCondition\":              ColumnCondition,\n\t\t\"Contains\":                     strings.Contains,\n\t\t\"ContractAccess\":               ContractAccess,\n\t\t\"RoleAccess\":                   RoleAccess,\n\t\t\"ContractConditions\":           ContractConditions,\n\t\t\"ContractName\":                 contractName,\n\t\t\"ValidateEditContractNewValue\": ValidateEditContractNewValue,\n\t\t\"CreateColumn\":                 CreateColumn,\n\t\t\"CreateTable\":                  CreateTable,\n\t\t\"DBInsert\":                     DBInsert,\n\t\t\"DBSelect\":                     DBSelect,\n\t\t\"DBUpdate\":                     DBUpdate,\n\t\t\"DBUpdatePlatformParam\":        UpdatePlatformParam,\n\t\t\"DBUpdateExt\":                  DBUpdateExt,\n\t\t\"EcosysParam\":                  EcosysParam,\n\t\t\"AppParam\":                     AppParam,\n\t\t\"SysParamString\":               SysParamString,\n\t\t\"SysParamInt\":                  SysParamInt,\n\t\t\"SysFuel\":                      SysFuel,\n\t\t\"Eval\":                         Eval,\n\t\t\"EvalCondition\":                EvalCondition,\n\t\t\"Float\":                        Float,\n\t\t\"GetContractByName\":            GetContractByName,\n\t\t\"GetContractById\":              GetContractById,\n\t\t\"HMac\":                         HMac,\n\t\t\"Join\":                         Join,\n\t\t\"JSONDecode\":                   JSONDecode,\n\t\t\"JSONEncode\":                   JSONEncode,\n\t\t\"JSONEncodeIndent\":             JSONEncodeIndent,\n\t\t\"IdToAddress\":                  converter.IDToAddress,\n\t\t\"Int\":                          Int,\n\t\t\"Len\":                          Len,\n\t\t\"Money\":                        Money,\n\t\t\"FormatMoney\":                  FormatMoney,\n\t\t\"PermColumn\":                   PermColumn,\n\t\t\"PermTable\":                    PermTable,\n\t\t\"Random\":                       RandomInt,\n\t\t\"RandomFloat\":                  RandomFloat,\n\t\t\"RandomDecimal\":                RandomDecimal,\n\t\t\"Split\":                        Split,\n\t\t\"Str\":                          Str,\n\t\t\"Substr\":                       Substr,\n\t\t\"Replace\":                      Replace,\n\t\t\"Size\":                         Size,\n\t\t\"PubToID\":                      PubToID,\n\t\t\"SeedToID\":                     crypto.AddressSeed,\n\t\t\"HexToBytes\":                   HexToBytes,\n\t\t\"LangRes\":                      LangRes,\n\t\t\"HasPrefix\":                    strings.HasPrefix,\n\t\t\"HasSlice\":                     HasSlice,\n\t\t\"ValidateCondition\":            ValidateCondition,\n\t\t\"TrimSpace\":                    strings.TrimSpace,\n\t\t\"ToLower\":                      strings.ToLower,\n\t\t\"ToUpper\":                      strings.ToUpper,\n\t\t\"CreateEcosystem\":              CreateEcosystem,\n\t\t\"CreateContract\":               CreateContract,\n\t\t\"UpdateContract\":               UpdateContract,\n\t\t\"TableConditions\":              TableConditions,\n\t\t\"CreateLanguage\":               CreateLanguage,\n\t\t\"EditLanguage\":                 EditLanguage,\n\t\t\"BndWallet\":                    BndWallet,\n\t\t\"UnbndWallet\":                  UnbndWallet,\n\t\t\"RowConditions\":                RowConditions,\n\t\t\"DecodeBase64\":                 DecodeBase64,\n\t\t\"EncodeBase64\":                 EncodeBase64,\n\t\t\"Hash\":                         Hash,\n\t\t\"DoubleHash\":                   crypto.DoubleHash,\n\t\t\"EditEcosysName\":               EditEcosysName,\n\t\t\"GetColumnType\":                GetColumnType,\n\t\t\"GetType\":                      GetType,\n\t\t\"AllowChangeCondition\":         AllowChangeCondition,\n\t\t\"StringToBytes\":                StringToBytes,\n\t\t\"BytesToString\":                BytesToString,\n\t\t\"GetMapKeys\":                   GetMapKeys,\n\t\t\"SortedKeys\":                   SortedKeys,\n\t\t\"Append\":                       Append,\n\t\t\"EthereumAddress\":              EthereumAddress,\n\t\t\"BitcoinLegacyAddress\":         BitcoinLegacyAddress, // 1 address public key uncompressed\n\t\t\"BitcoinBip32Address\":          BitcoinBip32Address,  // 1 address public key compressed\n\t\t\"BitcoinBip49Address\":          BitcoinBip49Address,  // 3 address public key compressed,path: m/49'/0'/0'/0/0\n\t\t\"BitcoinBip84Address\":          BitcoinBip84Address,  // bc1q address public key compressed,path: m/84'/0'/0'/0/0\n\t\t\"BitcoinBip86Address\":          BitcoinBip86Address,  // bc1p address public key compressed,path: m/86'/0'/0'/0/0\n\t\t\"TronAddress\":                  TronAddress,\n\t\t\"TopAmounts\":                   TopAmounts,\n\t\t\"GetLogTxCount\":                GetLogTxCount,\n\t\t\"GetHistory\":                   GetHistory,\n\t\t\"GetHistoryRow\":                GetHistoryRow,\n\t\t\"GetDataFromXLSX\":              GetDataFromXLSX,\n\t\t\"GetRowsCountXLSX\":             GetRowsCountXLSX,\n\t\t\"BlockTime\":                    BlockTime,\n\t\t\"IsObject\":                     IsObject,\n\t\t\"DateTime\":                     DateTime,\n\t\t\"AddDate\":                      AddDate,\n\t\t\"UnixDateTime\":                 UnixDateTime,\n\t\t\"DateTimeLocation\":             DateTimeLocation,\n\t\t\"UnixDateTimeLocation\":         UnixDateTimeLocation,\n\t\t\"UpdateNotifications\":          UpdateNotifications,\n\t\t\"UpdateRolesNotifications\":     UpdateRolesNotifications,\n\t\t\"DelTable\":                     DelTable,\n\t\t\"DelColumn\":                    DelColumn,\n\t\t\"HexToPub\":                     crypto.HexToPub,\n\t\t\"PubToHex\":                     PubToHex,\n\t\t\"UpdateNodesBan\":               UpdateNodesBan,\n\t\t\"Log\":                          Log,\n\t\t\"Log10\":                        Log10,\n\t\t\"Pow\":                          Pow,\n\t\t\"Sqrt\":                         Sqrt,\n\t\t\"Round\":                        Round,\n\t\t\"Floor\":                        Floor,\n\t\t\"CheckCondition\":               CheckCondition,\n\t\t\"IsHonorNodeKey\":               IsHonorNodeKey,\n\t\t\"CheckSign\":                    CheckSign,\n\t\t\"CheckNumberChars\":             CheckNumberChars,\n\t\t\"DateFormat\":                   Date,\n\t\t\"RegexpMatch\":                  RegexpMatch,\n\t\t\"DBCount\":                      DBCount,\n\t\t\"MathMod\":                      MathMod,\n\t\t\"MathModDecimal\":               MathModDecimal,\n\t\t\"CreateView\":                   CreateView,\n\t\t\"SqrtDecimal\":                  SqrtDecimal,\n\t\t\"Div\":                          Div,\n\t\t\"GreaterThan\":                  GreaterThan,\n\t\t\"GreaterThanOrEqual\":           GreaterThanOrEqual,\n\t\t\"LessThan\":                     LessThan,\n\t\t\"LessThanOrEqual\":              LessThanOrEqual,\n\t}\n\tswitch vt {\n\tcase script.VMType_CLB:\n\t\tf[\"HTTPRequest\"] = HTTPRequest\n\t\tf[\"Date\"] = Date\n\t\tf[\"HTTPPostJSON\"] = HTTPPostJSON\n\t\tf[\"ValidateCron\"] = ValidateCron\n\t\tf[\"UpdateCron\"] = UpdateCron\n\tcase script.VMType_CLBMaster:\n\t\tf[\"HTTPRequest\"] = HTTPRequest\n\t\tf[\"Date\"] = Date\n\t\tf[\"HTTPPostJSON\"] = HTTPPostJSON\n\t\tf[\"ValidateCron\"] = ValidateCron\n\t\tf[\"UpdateCron\"] = UpdateCron\n\t\tf[\"CreateCLB\"] = CreateCLB\n\t\tf[\"DeleteCLB\"] = DeleteCLB\n\t\tf[\"StartCLB\"] = StartCLB\n\t\tf[\"StopCLBProcess\"] = StopCLBProcess\n\t\tf[\"GetCLBList\"] = GetCLBList\n\tcase script.VMType_Smart:\n\t\tf[\"GetBlock\"] = GetBlock\n\t}\n\treturn f\n}\n\nfunc accessContracts(sc *SmartContract, names ...string) bool {\n\tcontract := sc.TxContract.StackCont[len(sc.TxContract.StackCont)-1].(string)\n\n\tfor _, item := range names {\n\t\tif contract == `@1`+item {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// CompileContract is compiling contract\nfunc CompileContract(sc *SmartContract, code string, state, id, token int64) (any, error) {\n\tif err := validateAccess(sc, \"CompileContract\"); err != nil {\n\t\treturn nil, err\n\t}\n\treturn sc.VM.CompileBlock([]rune(code), &script.OwnerInfo{StateID: uint32(state), WalletID: id, TokenID: token})\n}\n\n// ContractAccess checks whether the name of the executable contract matches one of the names listed in the parameters.\nfunc ContractAccess(sc *SmartContract, names ...any) bool {\n\tif conf.Config.FuncBench {\n\t\treturn true\n\t}\n\n\tfor _, iname := range names {\n\t\tswitch name := iname.(type) {\n\t\tcase string:\n\t\t\tif len(name) > 0 {\n\t\t\t\tif name[0] != '@' {\n\t\t\t\t\tname = fmt.Sprintf(`@%d`, sc.TxSmart.EcosystemID) + name\n\t\t\t\t}\n\t\t\t\tfor i := len(sc.TxContract.StackCont) - 1; i >= 0; i-- {\n\t\t\t\t\tcontName := sc.TxContract.StackCont[i].(string)\n\t\t\t\t\tif strings.HasPrefix(contName, `@`) {\n\t\t\t\t\t\tif contName == name {\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// RoleAccess checks whether the name of the role matches one of the names listed in the parameters.\nfunc RoleAccess(sc *SmartContract, ids ...any) (bool, error) {\n\trolesList, err := sqldb.GetMemberRoles(sc.DbTransaction, sc.TxSmart.EcosystemID, sc.Key.AccountID)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\trolesIndex := make(map[int64]bool)\n\tfor _, id := range rolesList {\n\t\trolesIndex[id] = true\n\t}\n\n\tfor _, id := range ids {\n\t\tswitch v := id.(type) {\n\t\tcase int64:\n\t\t\tif rolesIndex[v] {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// ContractConditions calls the 'conditions' function for each of the contracts specified in the parameters\nfunc ContractConditions(sc *SmartContract, names ...any) (bool, error) {\n\tfor _, iname := range names {\n\t\tname := iname.(string)\n\t\tif len(name) > 0 {\n\t\t\tcontractName := script.StateName(uint32(sc.TxSmart.EcosystemID), name)\n\t\t\tgetContract := VMGetContract(sc.VM, name, uint32(sc.TxSmart.EcosystemID))\n\t\t\tif getContract == nil {\n\t\t\t\tcontractName = script.StateName(0, name)\n\t\t\t\tgetContract = VMGetContract(sc.VM, name, 0)\n\t\t\t\tif getContract == nil {\n\t\t\t\t\treturn false, logErrorfShort(eUnknownContract, name, consts.NotFound)\n\t\t\t\t}\n\t\t\t}\n\t\t\tblock := getContract.GetFunc(`conditions`)\n\t\t\tif block == nil {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t\tvars := sc.getExtend()\n\t\t\t//if sc.TxContract == nil {\n\t\t\t//\tsc.TxContract = getContract\n\t\t\t//\tsc.TxContract.Extend = vars\n\t\t\t//}\n\t\t\tif err := sc.AppendStack(name); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tmethods := []string{`conditions`}\n\t\t\terr := script.RunContractByName(sc.VM, contractName, methods, vars, sc.Hash)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tsc.PopStack(name)\n\t\t} else {\n\t\t\treturn false, logError(errEmptyContract, consts.EmptyObject, \"ContractConditions\")\n\t\t}\n\t}\n\treturn true, nil\n}\n\nfunc contractName(value string) (name string, err error) {\n\tvar list []string\n\n\tlist, err = script.ContractsList(value)\n\tif err == nil && len(list) > 0 {\n\t\tname = list[0]\n\t}\n\treturn\n}\n\nfunc ValidateEditContractNewValue(sc *SmartContract, newValue, oldValue string) error {\n\tlist, err := script.ContractsList(newValue)\n\tif err != nil {\n\t\treturn err\n\t}\n\tcurlist, err := script.ContractsList(oldValue)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(list) != len(curlist) {\n\t\treturn errContractChange\n\t}\n\tfor i := 0; i < len(list); i++ {\n\t\tvar ok bool\n\t\tfor j := 0; j < len(curlist); j++ {\n\t\t\tif curlist[j] == list[i] {\n\t\t\t\tok = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !ok {\n\t\t\treturn errNameChange\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc UpdateContract(sc *SmartContract, id int64, value, conditions string, recipient int64, tokenID string) error {\n\tif err := validateAccess(sc, \"UpdateContract\"); err != nil {\n\t\treturn err\n\t}\n\tpars := make(map[string]any)\n\tecosystemID := sc.TxSmart.EcosystemID\n\tvar root any\n\tif len(value) > 0 {\n\t\tvar err error\n\t\troot, err = CompileContract(sc, value, ecosystemID, recipient, converter.StrToInt64(tokenID))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpars[\"value\"] = value\n\t}\n\tif len(conditions) > 0 {\n\t\tpars[\"conditions\"] = conditions\n\t}\n\n\tif len(pars) > 0 {\n\t\tif !sc.CLB {\n\t\t\tif err := SysRollback(sc, SysRollData{Type: \"EditContract\", ID: id}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif _, err := DBUpdate(sc, \"@1contracts\", id, types.LoadMap(pars)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif len(value) > 0 {\n\t\tif err := FlushContract(sc, root, id); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc CreateContract(sc *SmartContract, name, value, conditions string, tokenEcosystem, appID int64) (int64, error) {\n\tif err := validateAccess(sc, \"CreateContract\"); err != nil {\n\t\treturn 0, err\n\t}\n\tvar id int64\n\tvar err error\n\tisExists := GetContractByName(sc, name)\n\tif isExists != 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ContractError, \"name\": name,\n\t\t\t\"tableId\": isExists}).Error(\"create existing contract\")\n\t\treturn 0, fmt.Errorf(eContractExist, script.StateName(uint32(sc.TxSmart.EcosystemID), name))\n\t}\n\troot, err := CompileContract(sc, value, sc.TxSmart.EcosystemID, 0, tokenEcosystem)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\t_, id, err = DBInsert(sc, \"@1contracts\", types.LoadMap(map[string]any{\n\t\t\"name\":       name,\n\t\t\"value\":      value,\n\t\t\"conditions\": conditions,\n\t\t\"wallet_id\":  0,\n\t\t\"token_id\":   tokenEcosystem,\n\t\t\"app_id\":     appID,\n\t\t\"ecosystem\":  sc.TxSmart.EcosystemID,\n\t}))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif err = FlushContract(sc, root, id); err != nil {\n\t\treturn 0, err\n\t}\n\tif !sc.CLB {\n\t\terr = SysRollback(sc, SysRollData{Type: \"NewContract\", Data: value})\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\treturn id, nil\n}\n\nfunc getColumns(columns string) (colsSQL string, colout []byte, err error) {\n\tvar (\n\t\tsqlColType string\n\t\tcols       []any\n\t\tout        []byte\n\t)\n\tif err = unmarshalJSON([]byte(columns), &cols, \"columns from json\"); err != nil {\n\t\treturn\n\t}\n\tcolperm := make(map[string]string)\n\tcolList := make(map[string]bool)\n\tfor _, icol := range cols {\n\t\tvar data map[string]any\n\t\tswitch v := icol.(type) {\n\t\tcase string:\n\t\t\tif err = unmarshalJSON([]byte(v), &data, `columns permissions from json`); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\tdata = v.(map[string]any)\n\t\t}\n\t\tcolname := converter.EscapeSQL(strings.ToLower(data[`name`].(string)))\n\t\tif err = checkColumnName(colname); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif colList[colname] {\n\t\t\terr = errSameColumns\n\t\t\treturn\n\t\t}\n\n\t\tsqlColType, err = columnType(data[\"type\"].(string))\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tcolList[colname] = true\n\t\tcolsSQL += `\"` + colname + `\" ` + sqlColType + \" ,\\n\"\n\t\tcondition := ``\n\t\tswitch v := data[`conditions`].(type) {\n\t\tcase string:\n\t\t\tcondition = v\n\t\tcase map[string]any:\n\t\t\tout, err = marshalJSON(v, `conditions to json`)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcondition = string(out)\n\t\t}\n\t\tcolperm[colname] = condition\n\t}\n\tcolout, err = marshalJSON(colperm, `columns to json`)\n\treturn\n}\n\n// CreateView is creating smart contract view table\nfunc CreateView(sc *SmartContract, vname, columns, where string, applicationID int64) (err error) {\n\tif err = validateAccess(sc, \"CreateView\"); err != nil {\n\t\treturn\n\t}\n\tvar (\n\t\tviewName, tables, wheres, colSQLs string\n\t\tcolout, whsout                    []byte\n\t)\n\n\tviewName = qb.GetTableName(sc.TxSmart.EcosystemID, vname)\n\tvar check = sqldb.Namer{}\n\tif check.HasExists(sc.DbTransaction, viewName) {\n\t\treturn fmt.Errorf(eTableExists, vname)\n\t}\n\n\tcolSQLs, colout, err = parseViewColumnSql(sc, columns)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttables, wheres, whsout, err = parseViewWhereSql(sc, where)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err = sqldb.CreateView(sc.DbTransaction, viewName, tables, wheres, colSQLs); err != nil {\n\t\treturn logErrorDB(err, \"creating view table\")\n\t}\n\tprefix, name := PrefixName(viewName)\n\t_, _, err = sc.insert([]string{`name`, `columns`, `wheres`, `app_id`,\n\t\t`ecosystem`}, []any{name, string(colout), string(whsout),\n\t\tapplicationID, prefix}, `1_views`)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"insert table info\")\n\t}\n\tif !sc.CLB {\n\t\tif err = syspar.SysTableColType(sc.DbTransaction); err != nil {\n\t\t\treturn logErrorDB(err, \"updating sys table col type\")\n\t\t}\n\t\tif err = SysRollback(sc, SysRollData{Type: \"NewView\", TableName: viewName}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn\n}\n\ntype ViewColSch struct {\n\tTable string `json:\"table,omitempty\"`\n\tCol   string `json:\"col,omitempty\"`\n\tAlias string `json:\"alias,omitempty\"`\n}\n\nfunc parseViewColumnSql(sc *SmartContract, columns string) (colsSQL string, colout []byte, err error) {\n\tvar (\n\t\tcols, outarr []ViewColSch\n\t\tcolList      = make(map[string]bool)\n\t\thas          = make(map[string]bool)\n\t)\n\tif err = unmarshalJSON([]byte(columns), &cols, \"columns from json\"); err != nil {\n\t\treturn\n\t}\n\tif len(cols) == 0 {\n\t\terr = errors.New(\"columns is empty\")\n\t\treturn\n\t}\n\tfor i, icol := range cols {\n\t\tvar c ViewColSch\n\t\ttableName := converter.ParseTable(icol.Table, sc.TxSmart.EcosystemID)\n\t\tif !has[tableName] {\n\t\t\tif !sc.DbTransaction.HasTableOrView(tableName) {\n\t\t\t\terr = fmt.Errorf(eTableNotFound, tableName)\n\t\t\t\treturn\n\t\t\t}\n\t\t\thas[tableName] = true\n\t\t}\n\t\tcolname := converter.EscapeSQL(strings.ToLower(icol.Col))\n\t\tif err = checkColumnName(colname); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif colList[colname] {\n\t\t\terr = fmt.Errorf(\"column %s specified more than once\", colname)\n\t\t\treturn\n\t\t}\n\t\tc.Col = colname\n\t\talias := converter.EscapeSQL(strings.ToLower(icol.Alias))\n\t\tif len(alias) > 0 {\n\t\t\tif err = checkColumnName(alias); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcolname = colname + ` AS ` + alias\n\t\t}\n\t\tcolList[colname] = true\n\t\tw := `\"` + tableName + `\".` + colname\n\t\tif len(cols)-1 != i {\n\t\t\tcolsSQL += w + \",\\n\"\n\t\t} else {\n\t\t\tcolsSQL += w\n\t\t}\n\t\tc.Table = tableName\n\t\tc.Alias = alias\n\t\toutarr = append(outarr, c)\n\t}\n\tcolout, err = marshalJSON(outarr, `view columns to json`)\n\treturn\n}\n\ntype ViewWheSch struct {\n\tTableOne string `json:\"table1,omitempty\"`\n\tTableTwo string `json:\"table2,omitempty\"`\n\tColOne   string `json:\"col1,omitempty\"`\n\tColTwo   string `json:\"col2,omitempty\"`\n\tCompare  string `json:\"compare,omitempty\"`\n}\n\nfunc parseViewWhereSql(sc *SmartContract, columns string) (tabsSQL, whsSQL string, whsout []byte, err error) {\n\tvar (\n\t\tcols, outarr []ViewWheSch\n\t\ttabList      = make(map[string]bool)\n\t\ttableArr     = make([]string, 0)\n\t\thas          = make(map[string]bool)\n\t)\n\n\tif err = unmarshalJSON([]byte(columns), &cols, \"columns from json\"); err != nil {\n\t\treturn\n\t}\n\tif len(cols) == 0 {\n\t\terr = errors.New(\"columns is empty\")\n\t\treturn\n\t}\n\tremoveRepeated := func(arr []string) (newArr []string) {\n\t\tnewArr = make([]string, 0)\n\t\tsort.Strings(arr)\n\t\tfor i := 0; i < len(arr); i++ {\n\t\t\trepeat := false\n\t\t\tfor j := i + 1; j < len(arr); j++ {\n\t\t\t\tif arr[i] == arr[j] {\n\t\t\t\t\trepeat = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !repeat {\n\t\t\t\tnewArr = append(newArr, arr[i])\n\t\t\t}\n\t\t}\n\t\treturn newArr\n\t}\n\tfor i, icol := range cols {\n\t\ttableName1 := converter.ParseTable(icol.TableOne, sc.TxSmart.EcosystemID)\n\t\tif !has[tableName1] {\n\t\t\tif !sc.DbTransaction.HasTableOrView(tableName1) {\n\t\t\t\terr = fmt.Errorf(eTableNotFound, tableName1)\n\t\t\t\treturn\n\t\t\t}\n\t\t\thas[tableName1] = true\n\t\t}\n\t\ttableArr = append(tableArr, tableName1)\n\t\ttableName2 := converter.ParseTable(icol.TableTwo, sc.TxSmart.EcosystemID)\n\t\tif !has[tableName2] {\n\t\t\tif !sc.DbTransaction.HasTableOrView(tableName2) {\n\t\t\t\terr = fmt.Errorf(eTableNotFound, tableName2)\n\t\t\t\treturn\n\t\t\t}\n\t\t\thas[tableName2] = true\n\t\t}\n\t\ttableArr = append(tableArr, tableName2)\n\t\tcolName1 := converter.EscapeSQL(strings.ToLower(icol.ColOne))\n\t\tif err = checkColumnName(colName1); err != nil {\n\t\t\treturn\n\t\t}\n\t\tcolName2 := converter.EscapeSQL(strings.ToLower(icol.ColTwo))\n\t\tif err = checkColumnName(colName2); err != nil {\n\t\t\treturn\n\t\t}\n\t\tcompare := converter.EscapeSQL(strings.ToLower(icol.Compare))\n\t\tif len(compare) == 0 {\n\t\t\terr = errors.New(\"compare operator size is empty\")\n\t\t\treturn\n\t\t}\n\t\tw := `\"` + tableName1 + `\".` + colName1 + ` ` + compare + ` \"` + tableName2 + `\".` + colName2\n\t\tif len(cols)-1 != i {\n\t\t\twhsSQL += w + \" AND \"\n\t\t} else {\n\t\t\twhsSQL += w\n\t\t}\n\t\tvar c ViewWheSch\n\t\tc.TableOne = tableName1\n\t\tc.TableTwo = tableName2\n\t\tc.ColOne = colName1\n\t\tc.ColTwo = colName2\n\t\tc.Compare = compare\n\t\toutarr = append(outarr, c)\n\t}\n\tarr := removeRepeated(tableArr)\n\tfor i, tableName := range arr {\n\t\tif !tabList[tableName] {\n\t\t\tt := `\"` + tableName + `\"`\n\t\t\tif len(arr)-1 != i {\n\t\t\t\ttabsSQL += t + \",\"\n\t\t\t} else {\n\t\t\t\ttabsSQL += t\n\t\t\t}\n\t\t\ttabList[tableName] = true\n\t\t}\n\t}\n\twhsout, err = marshalJSON(outarr, `view wheres to json`)\n\treturn\n}\n\n// CreateTable is creating smart contract table\nfunc CreateTable(sc *SmartContract, name, columns, permissions string, applicationID int64) (err error) {\n\tif err := validateAccess(sc, \"CreateTable\"); err != nil {\n\t\treturn err\n\t}\n\n\tif len(name) == 0 {\n\t\treturn errTableEmptyName\n\t}\n\n\tif !converter.IsLatin(name) {\n\t\treturn fmt.Errorf(eLatin, name)\n\t}\n\n\tif (name[0] >= '0' && name[0] <= '9') || name[0] == '@' {\n\t\treturn errTableName\n\t}\n\n\ttableName := qb.GetTableName(sc.TxSmart.EcosystemID, name)\n\tif sc.DbTransaction.IsTable(tableName) {\n\t\treturn fmt.Errorf(eTableExists, name)\n\t}\n\n\tcolsSQL, colout, err := getColumns(columns)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = sqldb.CreateTable(sc.DbTransaction, tableName, strings.TrimRight(colsSQL, \",\\n\")); err != nil {\n\t\treturn logErrorDB(err, \"creating tables\")\n\t}\n\n\tvar perm permTable\n\tif err = unmarshalJSON([]byte(permissions), &perm, `permissions to json`); err != nil {\n\t\treturn err\n\t}\n\tpermout, err := marshalJSON(perm, `permissions to JSON`)\n\tif err != nil {\n\t\treturn err\n\t}\n\tprefix, name := PrefixName(tableName)\n\n\t_, _, err = sc.insert([]string{`name`, `columns`, `permissions`, `conditions`, `app_id`,\n\t\t`ecosystem`}, []any{name, string(colout), string(permout),\n\t\t`ContractAccess(\"@1EditTable\")`, applicationID, prefix}, `1_tables`)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"insert table info\")\n\t}\n\tif !sc.CLB {\n\t\tif err = syspar.SysTableColType(sc.DbTransaction); err != nil {\n\t\t\treturn logErrorDB(err, \"updating sys table col type\")\n\t\t}\n\t\tif err = SysRollback(sc, SysRollData{Type: \"NewTable\", TableName: tableName}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc columnType(colType string) (string, error) {\n\tif sqlColType, ok := typeToPSQL[colType]; ok {\n\t\treturn sqlColType, nil\n\t}\n\treturn ``, fmt.Errorf(eColumnType, colType)\n}\n\nfunc mapToParams(values *types.Map) (params []string, val []any, err error) {\n\tfor _, key := range values.Keys() {\n\t\tv, _ := values.Get(key)\n\t\tparams = append(params, converter.Sanitize(key, ` ->+`))\n\t\tval = append(val, v)\n\t}\n\tif len(params) == 0 {\n\t\terr = fmt.Errorf(`values are undefined`)\n\t}\n\treturn\n}\n\n// DBInsert inserts a record into the specified database table\nfunc DBInsert(sc *SmartContract, tblname string, values *types.Map) (qcost int64, ret int64, err error) {\n\tif tblname == \"platform_parameters\" {\n\t\treturn 0, 0, fmt.Errorf(\"platform parameters access denied\")\n\t}\n\n\ttblname = qb.GetTableName(sc.TxSmart.EcosystemID, tblname)\n\tif err = sc.AccessTable(tblname, \"insert\"); err != nil {\n\t\treturn\n\t}\n\tvar ind int\n\tvar lastID string\n\tif ind, err = sc.DbTransaction.NumIndexes(tblname); err != nil {\n\t\terr = logErrorDB(err, \"num indexes\")\n\t\treturn\n\t}\n\tparams, val, err := mapToParams(values)\n\tif err != nil {\n\t\treturn\n\t}\n\tif reflect.TypeOf(val[0]) == reflect.TypeOf([]any{}) {\n\t\tval = val[0].([]any)\n\t}\n\tqcost, lastID, err = sc.insert(params, val, tblname)\n\tif ind > 0 {\n\t\tqcost *= int64(ind)\n\t}\n\tif err == nil {\n\t\tret, _ = strconv.ParseInt(lastID, 10, 64)\n\t}\n\treturn\n}\n\n// PrepareColumns replaces jsonb fields -> in the list of columns for db selecting\n// For example, name,doc->title => name,doc::jsonb->>'title' as \"doc.title\"\nfunc PrepareColumns(columns []string) string {\n\tcolList := make([]string, 0)\n\tfor _, icol := range columns {\n\t\tif strings.Contains(icol, `->`) {\n\t\t\tcolfield := strings.Split(icol, `->`)\n\t\t\tif len(colfield) == 2 {\n\t\t\t\ticol = fmt.Sprintf(`%s::jsonb->>'%s' as \"%[1]s.%[2]s\"`, colfield[0], colfield[1])\n\t\t\t} else {\n\t\t\t\ticol = fmt.Sprintf(`%s::jsonb#>>'{%s}' as \"%[1]s.%[3]s\"`, colfield[0],\n\t\t\t\t\tstrings.Join(colfield[1:], `,`), strings.Join(colfield[1:], `.`))\n\t\t\t}\n\t\t} else if !strings.ContainsAny(icol, `:*>\"`) {\n\t\t\ticol = `\"` + icol + `\"`\n\t\t}\n\t\tcolList = append(colList, icol)\n\t}\n\treturn strings.Join(colList, `,`)\n}\n\n// DBSelect returns an array of values of the specified columns when there is selection of data 'offset', 'limit', 'where'\nfunc DBSelect(sc *SmartContract, tblname string, inColumns any, id int64, inOrder any,\n\toffset, limit int64, inWhere *types.Map, query any, group string, all bool) (int64, []any, error) {\n\n\tvar (\n\t\terr     error\n\t\trows    *sql.Rows\n\t\tperm    map[string]string\n\t\tcolumns []string\n\t\torder   string\n\t)\n\tcolumns, err = qb.GetColumns(inColumns)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\ttblname = qb.GetTableName(sc.TxSmart.EcosystemID, tblname)\n\twhere, err := qb.GetWhere(inWhere)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\tif id != 0 {\n\t\twhere = fmt.Sprintf(`id='%d'`, id)\n\t\tlimit = 1\n\t}\n\tif limit == 0 {\n\t\tlimit = 25\n\t}\n\tif limit < 0 || limit > consts.DBFindLimit {\n\t\tlimit = consts.DBFindLimit\n\t}\n\tperm, err = sc.AccessTablePerm(tblname, `read`)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\tif err = sc.AccessColumns(tblname, &columns, false); err != nil {\n\t\treturn 0, nil, err\n\t}\n\tq := sqldb.GetDB(sc.DbTransaction).Table(tblname).Select(PrepareColumns(columns)).Where(where)\n\n\t//group + order => false\n\t//group + no order => true\n\t//no group + order => true\n\t//no group + no order => true\n\torder, err = qb.GetOrder(tblname, inOrder, true)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\tif len(group) != 0 {\n\t\tq = q.Group(group)\n\t\tif inOrder != nil {\n\t\t\torder, err = qb.GetOrder(tblname, inOrder, false)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\tq = q.Order(order)\n\n\tif query != \"\" {\n\t\tq = q.Select(query)\n\t}\n\tif all {\n\t\trows, err = q.Rows()\n\t} else {\n\t\trows, err = q.Offset(int(offset)).Limit(int(limit)).Rows()\n\t}\n\tif err != nil {\n\t\treturn 0, nil, logErrorDB(err, fmt.Sprintf(\"selecting rows from table %s %s where %s order %s\",\n\t\t\ttblname, PrepareColumns(columns), where, order))\n\t}\n\tdefer rows.Close()\n\tcols, err := rows.Columns()\n\tif err != nil {\n\t\treturn 0, nil, logErrorDB(err, \"getting rows columns\")\n\t}\n\tvalues := make([][]byte, len(cols))\n\tscanArgs := make([]any, len(values))\n\tfor i := range values {\n\t\tscanArgs[i] = &values[i]\n\t}\n\n\tresult := make([]any, 0, 50)\n\tfor rows.Next() {\n\t\terr = rows.Scan(scanArgs...)\n\t\tif err != nil {\n\t\t\treturn 0, nil, logErrorDB(err, \"scanning next row\")\n\t\t}\n\t\trow := types.NewMap()\n\t\tfor i, col := range values {\n\t\t\tvar value string\n\t\t\tif col != nil {\n\t\t\t\tvalue = string(col)\n\t\t\t}\n\t\t\trow.Set(cols[i], value)\n\t\t}\n\t\tresult = append(result, reflect.ValueOf(row).Interface())\n\t}\n\tif perm != nil && len(perm[`filter`]) > 0 {\n\t\tfltResult, err := sc.VM.EvalIf(perm[`filter`], uint32(sc.TxSmart.EcosystemID),\n\t\t\tsc.getExtend(),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn 0, nil, err\n\t\t}\n\t\tif !fltResult {\n\t\t\tlog.WithFields(log.Fields{\"filter\": perm[\"filter\"]}).Error(\"Access denied\")\n\t\t\treturn 0, nil, errAccessDenied\n\t\t}\n\t}\n\treturn 0, result, nil\n}\n\n// DBUpdateExt updates the record in the specified table. You can specify 'where' query in params and then the values for this query\nfunc DBUpdateExt(sc *SmartContract, tblname string, where *types.Map,\n\tvalues *types.Map) (qcost int64, err error) {\n\tif tblname == \"platform_parameters\" {\n\t\treturn 0, fmt.Errorf(\"platform parameters access denied\")\n\t}\n\ttblname = qb.GetTableName(sc.TxSmart.EcosystemID, tblname)\n\tif err = sc.AccessTable(tblname, \"update\"); err != nil {\n\t\treturn\n\t}\n\tcolumns, val, err := mapToParams(values)\n\tif err != nil {\n\t\treturn\n\t}\n\tif err = sc.AccessColumns(tblname, &columns, true); err != nil {\n\t\treturn\n\t}\n\tqcost, _, err = sc.updateWhere(columns, val, tblname, where)\n\treturn\n}\n\n// DBUpdate updates the item with the specified id in the table\nfunc DBUpdate(sc *SmartContract, tblname string, id int64, values *types.Map) (qcost int64, err error) {\n\treturn DBUpdateExt(sc, tblname, types.LoadMap(map[string]any{`id`: id}), values)\n}\n\n// EcosysParam returns the value of the specified parameter for the ecosystem\nfunc EcosysParam(sc *SmartContract, name string) string {\n\tsp := &sqldb.StateParameter{}\n\tsp.SetTablePrefix(converter.Int64ToStr(sc.TxSmart.EcosystemID))\n\t_, err := sp.Get(nil, name)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"getting ecosystem param\").Error()\n\t}\n\treturn sp.Value\n}\n\n// AppParam returns the value of the specified app parameter for the ecosystem\nfunc AppParam(sc *SmartContract, app int64, name string, ecosystem int64) (string, error) {\n\tap := &sqldb.AppParam{}\n\tap.SetTablePrefix(converter.Int64ToStr(ecosystem))\n\t_, err := ap.Get(sc.DbTransaction, app, name)\n\tif err != nil {\n\t\treturn ``, logErrorDB(err, \"getting app param\")\n\t}\n\treturn ap.Value, nil\n}\n\n// Eval evaluates the condition\nfunc Eval(sc *SmartContract, condition string) error {\n\tif len(condition) == 0 {\n\t\treturn logErrorShort(errEmptyCond, consts.EmptyObject)\n\t}\n\tret, err := sc.EvalIf(condition)\n\tif err != nil {\n\t\treturn logError(err, consts.EvalError, \"eval condition\")\n\t}\n\tif !ret {\n\t\treturn logErrorShort(errAccessDenied, consts.AccessDenied)\n\t}\n\treturn nil\n}\n\n// CheckCondition evaluates the condition\nfunc CheckCondition(sc *SmartContract, condition string) (bool, error) {\n\tif len(condition) == 0 {\n\t\treturn false, nil\n\t}\n\tret, err := sc.EvalIf(condition)\n\tif err != nil {\n\t\treturn false, logError(err, consts.EvalError, \"eval condition\")\n\t}\n\treturn ret, nil\n}\n\n// FlushContract is flushing contract\nfunc FlushContract(sc *SmartContract, iroot any, id int64) error {\n\tif err := validateAccess(sc, \"FlushContract\"); err != nil {\n\t\treturn err\n\t}\n\troot := iroot.(*script.CodeBlock)\n\tif id != 0 {\n\t\tif len(root.Children) != 1 || root.Children[0].Type != script.ObjectType_Contract {\n\t\t\treturn errOneContract\n\t\t}\n\t}\n\tfor i, item := range root.Children {\n\t\tif item.Type == script.ObjectType_Contract {\n\t\t\troot.Children[i].GetContractInfo().Owner.TableID = id\n\t\t}\n\t}\n\tfor key, item := range root.Objects {\n\t\tif cur, ok := sc.VM.Objects[key]; ok {\n\t\t\tvar id uint32\n\t\t\tswitch item.Type {\n\t\t\tcase script.ObjectType_Contract:\n\t\t\t\tid = cur.GetCodeBlock().GetContractInfo().ID\n\t\t\tcase script.ObjectType_Func:\n\t\t\t\tid = cur.GetCodeBlock().GetFuncInfo().ID\n\t\t\t}\n\t\t\tsc.FlushRollback = append(sc.FlushRollback, &FlushInfo{\n\t\t\t\tID:   id,\n\t\t\t\tPrev: sc.VM.Children[id],\n\t\t\t\tInfo: cur,\n\t\t\t\tName: key,\n\t\t\t})\n\t\t} else {\n\t\t\tsc.FlushRollback = append(sc.FlushRollback, &FlushInfo{\n\t\t\t\tID:   uint32(len(sc.VM.Children)),\n\t\t\t\tPrev: nil,\n\t\t\t\tInfo: nil,\n\t\t\t\tName: key,\n\t\t\t})\n\t\t}\n\n\t}\n\tsc.VM.FlushBlock(root)\n\treturn nil\n}\n\n// IsObject returns true if there is the specified contract\nfunc IsObject(sc *SmartContract, name string, state int64) bool {\n\treturn script.VMObjectExists(sc.VM, name, uint32(state))\n}\n\n// Len returns the length of the slice\nfunc Len(in []any) int64 {\n\tif in == nil {\n\t\treturn 0\n\t}\n\treturn int64(len(in))\n}\n\n// PermTable is changing permission of table\nfunc PermTable(sc *SmartContract, name, permissions string) error {\n\tif err := validateAccess(sc, \"PermTable\"); err != nil {\n\t\treturn err\n\t}\n\tvar perm permTable\n\tif err := unmarshalJSON([]byte(permissions), &perm, `table permissions to json`); err != nil {\n\t\treturn err\n\t}\n\tpermout, err := marshalJSON(perm, `permission list to json`)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tname = converter.EscapeSQL(strings.ToLower(name))\n\ttbl := &sqldb.Table{}\n\ttbl.SetTablePrefix(converter.Int64ToStr(sc.TxSmart.EcosystemID))\n\tfound, err := tbl.Get(sc.DbTransaction, name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !found {\n\t\treturn fmt.Errorf(eTableNotFound, name)\n\t}\n\t_, _, err = sc.update([]string{`permissions`}, []any{string(permout)},\n\t\t`1_tables`, `id`, tbl.ID)\n\treturn err\n}\n\nfunc columnConditions(sc *SmartContract, columns string) (err error) {\n\tvar cols []any\n\tif err = unmarshalJSON([]byte(columns), &cols, \"columns permissions from json\"); err != nil {\n\t\treturn\n\t}\n\tif len(cols) == 0 {\n\t\treturn logErrorShort(errUndefColumns, consts.EmptyObject)\n\t}\n\tif len(cols) > syspar.GetMaxColumns() {\n\t\treturn logErrorfShort(eManyColumns, syspar.GetMaxColumns(), consts.ParameterExceeded)\n\t}\n\tfor _, icol := range cols {\n\t\tvar data map[string]any\n\t\tswitch v := icol.(type) {\n\t\tcase string:\n\t\t\tif err = unmarshalJSON([]byte(v), &data, `columns permissions from json`); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tdata = v.(map[string]any)\n\t\t}\n\t\tif data[`name`] == nil || data[`type`] == nil {\n\t\t\treturn logErrorShort(errWrongColumn, consts.InvalidObject)\n\t\t}\n\t\tif len(typeToPSQL[data[`type`].(string)]) == 0 {\n\t\t\treturn logErrorShort(errIncorrectType, consts.InvalidObject)\n\t\t}\n\t\tcondition := ``\n\t\tswitch v := data[`conditions`].(type) {\n\t\tcase string:\n\t\t\tcondition = v\n\t\tcase map[string]any:\n\t\t\tout, err := marshalJSON(v, `conditions to json`)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcondition = string(out)\n\t\t}\n\t\tperm, err := getPermColumns(condition)\n\t\tif err != nil {\n\t\t\treturn logError(err, consts.EmptyObject, \"Conditions is empty\")\n\t\t}\n\t\tif len(perm.Update) == 0 {\n\t\t\treturn logErrorShort(errConditionEmpty, consts.EmptyObject)\n\t\t}\n\t\tif err = script.VMCompileEval(sc.VM, perm.Update, uint32(sc.TxSmart.EcosystemID)); err != nil {\n\t\t\treturn logError(err, consts.EvalError, \"compile update conditions\")\n\t\t}\n\t\tif len(perm.Read) > 0 {\n\t\t\tif err = script.VMCompileEval(sc.VM, perm.Read, uint32(sc.TxSmart.EcosystemID)); err != nil {\n\t\t\t\treturn logError(err, consts.EvalError, \"compile read conditions\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// TableConditions is contract func\nfunc TableConditions(sc *SmartContract, name, columns, permissions string) (err error) {\n\tisEdit := len(columns) == 0\n\tname = strings.ToLower(name)\n\tif err := validateAccess(sc, \"TableConditions\"); err != nil {\n\t\treturn err\n\t}\n\n\tprefix := converter.Int64ToStr(sc.TxSmart.EcosystemID)\n\n\tt := &sqldb.Table{}\n\tt.SetTablePrefix(prefix)\n\texists, err := t.Get(sc.DbTransaction, name)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"table exists\")\n\t}\n\tif isEdit {\n\t\tif !exists {\n\t\t\treturn logErrorfShort(eTableNotFound, name, consts.NotFound)\n\t\t}\n\t} else if exists {\n\t\treturn logErrorfShort(eTableExists, name, consts.Found)\n\t}\n\t_, err = qb.GetColumns(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar perm permTable\n\tif err = unmarshalJSON([]byte(permissions), &perm, \"permissions from json\"); err != nil {\n\t\treturn err\n\t}\n\tv := reflect.ValueOf(perm)\n\tfor i := 0; i < v.NumField(); i++ {\n\t\tcond := v.Field(i).Interface().(string)\n\t\tname := v.Type().Field(i).Name\n\t\tif len(cond) == 0 && name != `Read` && name != `Filter` {\n\t\t\treturn logErrorfShort(eEmptyCond, name, consts.EmptyObject)\n\t\t}\n\t\tif err = script.VMCompileEval(sc.VM, cond, uint32(sc.TxSmart.EcosystemID)); err != nil {\n\t\t\treturn logError(err, consts.EvalError, \"compile evaluating permissions\")\n\t\t}\n\t}\n\n\tif isEdit {\n\t\tif err = sc.AccessTable(name, `update`); err != nil {\n\t\t\tif err = sc.AccessRights(`changing_tables`, false); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\tif err := columnConditions(sc, columns); err != nil {\n\t\treturn err\n\t}\n\tif err := sc.AccessRights(\"new_table\", false); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// ValidateCondition checks if the condition can be compiled\nfunc ValidateCondition(sc *SmartContract, condition string, state int64) error {\n\tif len(condition) == 0 {\n\t\treturn logErrorShort(errConditionEmpty, consts.EmptyObject)\n\t}\n\treturn script.VMCompileEval(sc.VM, condition, uint32(state))\n}\n\n// ColumnCondition is contract func\nfunc ColumnCondition(sc *SmartContract, tableName, name, coltype, permissions string) error {\n\tname = converter.EscapeSQL(strings.ToLower(name))\n\ttableName = converter.EscapeSQL(strings.ToLower(tableName))\n\tif err := validateAccess(sc, \"ColumnCondition\"); err != nil {\n\t\treturn err\n\t}\n\n\tisExist := accessContracts(sc, nEditColumn)\n\ttEx := &sqldb.Table{}\n\tprefix := converter.Int64ToStr(sc.TxSmart.EcosystemID)\n\ttEx.SetTablePrefix(prefix)\n\n\texists, err := tEx.IsExistsByPermissionsAndTableName(sc.DbTransaction, name, tableName)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"querying that table is exists by permissions and table name\")\n\t}\n\tif isExist {\n\t\tif !exists {\n\t\t\treturn logErrorfShort(eColumnNotExist, name, consts.NotFound)\n\t\t}\n\t} else if exists {\n\t\treturn logErrorfShort(eColumnExist, name, consts.Found)\n\t}\n\t_, err = qb.GetColumns(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(permissions) == 0 {\n\t\treturn logErrorShort(errPermEmpty, consts.EmptyObject)\n\t}\n\tperm, err := getPermColumns(permissions)\n\tif err = script.VMCompileEval(sc.VM, perm.Update, uint32(sc.TxSmart.EcosystemID)); err != nil {\n\t\treturn err\n\t}\n\tif len(perm.Read) > 0 {\n\t\tif err = script.VMCompileEval(sc.VM, perm.Read, uint32(sc.TxSmart.EcosystemID)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\ttblName := qb.GetTableName(sc.TxSmart.EcosystemID, tableName)\n\tif isExist {\n\t\treturn nil\n\t}\n\tcount, err := sc.DbTransaction.GetColumnCount(tblName)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"counting table columns\")\n\t}\n\tif count >= int64(syspar.GetMaxColumns()) {\n\t\treturn logErrorfShort(eManyColumns, syspar.GetMaxColumns(), consts.ParameterExceeded)\n\t}\n\tif len(typeToPSQL[coltype]) == 0 {\n\t\treturn logErrorValue(errIncorrectType, consts.InvalidObject, \"Unknown column type\", coltype)\n\t}\n\treturn sc.AccessTable(tblName, \"new_column\")\n}\n\n// AllowChangeCondition check access to change condition throught supper contract\nfunc AllowChangeCondition(sc *SmartContract, tblname string) error {\n\t_, name := converter.ParseName(tblname)\n\tif param, ok := tableParamConditions[name]; ok {\n\t\treturn sc.AccessRights(param, false)\n\t}\n\n\treturn nil\n}\n\n// RowConditions checks conditions for table row by id\nfunc RowConditions(sc *SmartContract, tblname string, id int64, conditionOnly bool) error {\n\tcondition, err := sc.DbTransaction.GetRowConditionsByTableNameAndID(\n\t\tqb.GetTableName(sc.TxSmart.EcosystemID, tblname), id)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"executing row condition query\")\n\t}\n\n\tif len(condition) == 0 {\n\t\treturn logErrorValue(fmt.Errorf(eItemNotFound, id), consts.NotFound,\n\t\t\t\"record not found\", tblname)\n\t}\n\n\tfor _, v := range sc.TxContract.StackCont {\n\t\tif v == condition {\n\t\t\treturn errRecursion\n\t\t}\n\t}\n\n\tif err := Eval(sc, condition); err != nil {\n\t\tif err == errAccessDenied && conditionOnly {\n\t\t\treturn AllowChangeCondition(sc, tblname)\n\t\t}\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc checkColumnName(name string) error {\n\tif len(name) == 0 {\n\t\treturn errEmptyColumn\n\t} else if name[0] >= '0' && name[0] <= '9' {\n\t\treturn errWrongColumn\n\t}\n\tif !converter.IsLatin(name) {\n\t\treturn fmt.Errorf(eLatin, name)\n\t}\n\treturn nil\n}\n\nfunc checkTableNameRule(name string) error {\n\tif len(name) == 0 {\n\t\treturn errTableEmptyName\n\t}\n\tif (name[0] >= '0' && name[0] <= '9') || name[0] == '@' {\n\t\treturn errTableName\n\t}\n\tif !converter.IsLatin(name) {\n\t\treturn fmt.Errorf(eLatin, name)\n\t}\n\treturn nil\n}\n\n// CreateColumn is creating column\nfunc CreateColumn(sc *SmartContract, tableName, name, colType, permissions string) (err error) {\n\tvar (\n\t\tsqlColType string\n\t\tpermout    []byte\n\t)\n\tif err = validateAccess(sc, \"CreateColumn\"); err != nil {\n\t\treturn\n\t}\n\tname = converter.EscapeSQL(strings.ToLower(name))\n\tif err = checkColumnName(name); err != nil {\n\t\treturn\n\t}\n\n\ttblname := qb.GetTableName(sc.TxSmart.EcosystemID, tableName)\n\n\tsqlColType, err = columnType(colType)\n\n\tif err != nil {\n\t\treturn\n\t}\n\n\terr = sc.DbTransaction.AlterTableAddColumn(tblname, name, sqlColType)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"adding column to the table\")\n\t}\n\n\ttype cols struct {\n\t\tID      int64\n\t\tColumns string\n\t}\n\ttemp := &cols{}\n\terr = sqldb.GetDB(sc.DbTransaction).Table(`1_tables`).Where(\"name = ? and ecosystem = ?\",\n\t\tstrings.ToLower(tableName), sc.TxSmart.EcosystemID).Select(\"id,columns\").Find(temp).Error\n\n\tif err != nil {\n\t\treturn\n\t}\n\tvar perm map[string]string\n\tif err = unmarshalJSON([]byte(temp.Columns), &perm, `columns from the table`); err != nil {\n\t\treturn err\n\t}\n\tperm[name] = permissions\n\tpermout, err = marshalJSON(perm, `permissions to json`)\n\tif err != nil {\n\t\treturn\n\t}\n\t_, _, err = sc.update([]string{`columns`}, []any{string(permout)},\n\t\t`1_tables`, `id`, temp.ID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !sc.CLB {\n\t\tif err := syspar.SysTableColType(sc.DbTransaction); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn SysRollback(sc, SysRollData{Type: \"NewColumn\", TableName: tblname, Data: name})\n\t}\n\treturn\n}\n\n// PermColumn is contract func\nfunc PermColumn(sc *SmartContract, tableName, name, permissions string) error {\n\tif err := validateAccess(sc, \"PermColumn\"); err != nil {\n\t\treturn err\n\t}\n\tname = converter.EscapeSQL(strings.ToLower(name))\n\ttableName = converter.EscapeSQL(strings.ToLower(tableName))\n\ttables := `1_tables`\n\ttype cols struct {\n\t\tColumns string\n\t}\n\ttemp := &cols{}\n\terr := sqldb.GetDB(sc.DbTransaction).Table(tables).Where(\"name = ?\", tableName).Select(\"columns\").Find(temp).Error\n\tif err != nil {\n\t\treturn logErrorDB(err, \"querying columns by table name\")\n\t}\n\tvar perm map[string]string\n\tif err = unmarshalJSON([]byte(temp.Columns), &perm, `columns from json`); err != nil {\n\t\treturn err\n\t}\n\tperm[name] = permissions\n\tpermout, err := marshalJSON(perm, `column permissions to json`)\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, _, err = sc.update([]string{`columns`}, []any{string(permout)},\n\t\ttables, `name`, tableName)\n\treturn err\n}\n\n// HMac returns HMAC hash as raw or hex string\nfunc HMac(key, data string, raw_output bool) (ret string, err error) {\n\thash, err := crypto.GetHMAC(key, data)\n\tif err != nil {\n\t\treturn ``, logError(err, consts.CryptoError, \"getting HMAC\")\n\t}\n\tif raw_output {\n\t\treturn string(hash), nil\n\t}\n\treturn hex.EncodeToString(hash), nil\n}\n\n// GetMapKeys returns the array of keys of the map\nfunc GetMapKeys(in *types.Map) []any {\n\tkeys := make([]any, 0, in.Size())\n\tfor _, k := range in.Keys() {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys\n}\n\n// SortedKeys returns the sorted array of keys of the map\nfunc SortedKeys(m *types.Map) []any {\n\ti, sorted := 0, make([]string, m.Size())\n\tfor _, k := range m.Keys() {\n\t\tsorted[i] = k\n\t\ti++\n\t}\n\tsort.Strings(sorted)\n\n\tret := make([]any, len(sorted))\n\tfor k, v := range sorted {\n\t\tret[k] = v\n\t}\n\treturn ret\n}\n\nfunc httpRequest(req *http.Request, headers map[string]any) (string, error) {\n\tfor key, v := range headers {\n\t\treq.Header.Set(key, fmt.Sprint(v))\n\t}\n\tclient := &http.Client{}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn ``, logError(err, consts.NetworkError, \"http request\")\n\t}\n\tdefer resp.Body.Close()\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn ``, logError(err, consts.IOError, \"reading http answer\")\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn ``, logError(fmt.Errorf(`%d %s`, resp.StatusCode, strings.TrimSpace(string(data))),\n\t\t\tconsts.NetworkError, \"http status code\")\n\t}\n\treturn string(data), nil\n}\n\n// HTTPRequest sends http request\nfunc HTTPRequest(requrl, method string, head *types.Map, params *types.Map) (string, error) {\n\n\tvar ioform io.Reader\n\n\theaders := make(map[string]any)\n\tfor _, key := range head.Keys() {\n\t\tv, _ := head.Get(key)\n\t\theaders[key] = v\n\t}\n\tform := &url.Values{}\n\tfor _, key := range params.Keys() {\n\t\tv, _ := params.Get(key)\n\t\tform.Set(key, fmt.Sprint(v))\n\t}\n\tif len(*form) > 0 {\n\t\tioform = strings.NewReader(form.Encode())\n\t}\n\treq, err := http.NewRequest(method, requrl, ioform)\n\tif err != nil {\n\t\treturn ``, logError(err, consts.NetworkError, \"new http request\")\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\treturn httpRequest(req, headers)\n}\n\n// HTTPPostJSON sends post http request with json\nfunc HTTPPostJSON(requrl string, head *types.Map, json_str string) (string, error) {\n\treq, err := http.NewRequest(\"POST\", requrl, bytes.NewBuffer([]byte(json_str)))\n\tif err != nil {\n\t\treturn ``, logError(err, consts.NetworkError, \"new http request\")\n\t}\n\theaders := make(map[string]any)\n\tfor _, key := range head.Keys() {\n\t\tv, _ := head.Get(key)\n\t\theaders[key] = v\n\t}\n\treturn httpRequest(req, headers)\n}\n\n// RandomInt returns a random value between min and max\nfunc RandomInt(sc *SmartContract, min int64, max int64) (int64, error) {\n\tif min < 0 || max < 0 || min >= max {\n\t\treturn 0, logError(fmt.Errorf(eWrongRandom, min, max), consts.InvalidObject, \"getting random\")\n\t}\n\treturn min + sc.Rand.Int63n(max-min), nil\n}\n\nfunc RandomFloat(sc *SmartContract, min float64, max float64) (float64, error) {\n\tif min < 0 || max < 0 || min >= max {\n\t\treturn 0, logError(fmt.Errorf(eWrongRandom, min, max), consts.InvalidObject, \"getting random\")\n\t}\n\treturn min + sc.Rand.Float64()*(max-min), nil\n}\n\nfunc RandomDecimal(sc *SmartContract, min decimal.Decimal, max decimal.Decimal) (decimal.Decimal, error) {\n\tif min.LessThan(decimal.Zero) || max.LessThan(decimal.Zero) || min.GreaterThanOrEqual(max) {\n\t\treturn decimal.Zero, logError(fmt.Errorf(eWrongRandom, min, max), consts.InvalidObject, \"getting random\")\n\t}\n\treturn decimal.NewFromFloat(sc.Rand.Float64()).Mul(max.Sub(min)).Add(min).Floor(), nil\n}\n\nfunc ValidateCron(cronSpec string) (err error) {\n\t_, err = scheduler.Parse(cronSpec)\n\treturn\n}\n\nfunc UpdateCron(sc *SmartContract, id int64) error {\n\tcronTask := &sqldb.Cron{}\n\tcronTask.SetTablePrefix(converter.Int64ToStr(sc.TxSmart.EcosystemID))\n\n\tok, err := cronTask.Get(id)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"get cron record\")\n\t}\n\n\tif !ok {\n\t\treturn nil\n\t}\n\n\terr = scheduler.UpdateTask(&scheduler.Task{\n\t\tID:       cronTask.UID(),\n\t\tCronSpec: cronTask.Cron,\n\t\tHandler: &contract.ContractHandler{\n\t\t\tContract: cronTask.Contract,\n\t\t},\n\t})\n\treturn err\n}\n\nfunc UpdateNodesBan(smartContract *SmartContract, timestamp int64) error {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn ErrNotImplementedOnCLB\n\t}\n\n\tnow := time.Unix(timestamp, 0)\n\n\tbadBlocks := &sqldb.BadBlocks{}\n\tbanRequests, err := badBlocks.GetNeedToBanNodes(now, syspar.GetIncorrectBlocksPerDay())\n\tif err != nil {\n\t\tlogError(err, consts.DBError, \"get nodes need to be banned\")\n\t\treturn err\n\t}\n\n\thonorNodes := syspar.GetNodes()\n\tvar updHonorNodes bool\n\tfor i, honorNode := range honorNodes {\n\t\t// Removing ban in case ban time has already passed\n\t\tif honorNode.UnbanTime.Unix() > 0 && now.After(honorNode.UnbanTime) {\n\t\t\thonorNode.UnbanTime = time.Unix(0, 0)\n\t\t\tupdHonorNodes = true\n\t\t}\n\t\tnodeKeyID := crypto.Address(honorNode.PublicKey)\n\n\t\t// Setting ban time if we have ban requests for the current node from 51% of all nodes.\n\t\t// Ban request is mean that node have added more or equal N(system parameter) of bad blocks\n\t\tfor _, banReq := range banRequests {\n\t\t\tif banReq.ProducerNodeId == nodeKeyID && banReq.Count >= int64((len(honorNodes)/2)+1) {\n\t\t\t\thonorNode.UnbanTime = now.Add(syspar.GetNodeBanTime())\n\n\t\t\t\tblocks, err := badBlocks.GetNodeBlocks(nodeKeyID, now)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn logErrorDB(err, \"getting node bad blocks for removing\")\n\t\t\t\t}\n\n\t\t\t\tfor _, b := range blocks {\n\t\t\t\t\tif _, err := DBUpdate(smartContract, \"@1bad_blocks\", b.ID,\n\t\t\t\t\t\ttypes.LoadMap(map[string]any{\"deleted\": \"1\"})); err != nil {\n\t\t\t\t\t\treturn logErrorValue(err, consts.DBError, \"deleting bad block\",\n\t\t\t\t\t\t\tconverter.Int64ToStr(b.ID))\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbanMessage := fmt.Sprintf(\n\t\t\t\t\t\"%d/%d nodes voted for ban with %d or more blocks each\",\n\t\t\t\t\tbanReq.Count,\n\t\t\t\t\tlen(honorNodes),\n\t\t\t\t\tsyspar.GetIncorrectBlocksPerDay(),\n\t\t\t\t)\n\n\t\t\t\t_, _, err = DBInsert(\n\t\t\t\t\tsmartContract,\n\t\t\t\t\t\"@1node_ban_logs\",\n\t\t\t\t\ttypes.LoadMap(map[string]any{\n\t\t\t\t\t\t\"node_id\":   nodeKeyID,\n\t\t\t\t\t\t\"banned_at\": now.Format(time.RFC3339),\n\t\t\t\t\t\t\"ban_time\":  int64(syspar.GetNodeBanTime() / time.Millisecond), // in ms\n\t\t\t\t\t\t\"reason\":    banMessage,\n\t\t\t\t\t}))\n\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn logErrorValue(err, consts.DBError, \"inserting log to node_ban_log\",\n\t\t\t\t\t\tconverter.Int64ToStr(banReq.ProducerNodeId))\n\t\t\t\t}\n\n\t\t\t\t_, _, err = DBInsert(\n\t\t\t\t\tsmartContract,\n\t\t\t\t\t\"@1notifications\",\n\t\t\t\t\ttypes.LoadMap(map[string]any{\n\t\t\t\t\t\t\"recipient->member_id\": nodeKeyID,\n\t\t\t\t\t\t\"notification->type\":   sqldb.NotificationTypeSingle,\n\t\t\t\t\t\t\"notification->header\": nodeBanNotificationHeader,\n\t\t\t\t\t\t\"notification->body\":   banMessage,\n\t\t\t\t\t}))\n\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn logErrorValue(err, consts.DBError, \"inserting log to node_ban_log\",\n\t\t\t\t\t\tconverter.Int64ToStr(banReq.ProducerNodeId))\n\t\t\t\t}\n\n\t\t\t\tupdHonorNodes = true\n\t\t\t}\n\t\t}\n\n\t\thonorNodes[i] = honorNode\n\t}\n\n\tif updHonorNodes {\n\t\tdata, err := marshalJSON(honorNodes, `honor nodes`)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = UpdatePlatformParam(smartContract, syspar.HonorNodes, string(data), \"\")\n\t\tif err != nil {\n\t\t\treturn logErrorDB(err, \"updating honor nodes\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc GetBlock(blockID int64) (*types.Map, error) {\n\tblock := sqldb.BlockChain{}\n\tok, err := block.Get(blockID)\n\tif err != nil {\n\t\treturn nil, logErrorDB(err, \"getting block\")\n\t}\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\n\treturn types.LoadMap(map[string]any{\n\t\t\"id\":     block.ID,\n\t\t\"time\":   block.Time,\n\t\t\"key_id\": block.KeyID,\n\t}), nil\n}\n\n// DecodeBase64 decodes base64 string\nfunc DecodeBase64(input string) (out string, err error) {\n\tvar bin []byte\n\tbin, err = base64.StdEncoding.DecodeString(input)\n\tif err == nil {\n\t\tout = string(bin)\n\t}\n\treturn\n}\n\n// EncodeBase64 encodes string in base64\nfunc EncodeBase64(input string) (out string) {\n\treturn base64.StdEncoding.EncodeToString([]byte(input))\n}\n\n// Hash returns hash sum of data\nfunc Hash(data any) (string, error) {\n\tvar b []byte\n\n\tswitch v := data.(type) {\n\tcase []uint8:\n\t\tb = v\n\tcase string:\n\t\tb = []byte(v)\n\tdefault:\n\t\treturn \"\", logErrorf(eUnsupportedType, v, consts.ConversionError, \"converting to bytes\")\n\t}\n\n\thash := crypto.Hash(b)\n\n\treturn hex.EncodeToString(hash[:]), nil\n}\n\n// GetColumnType returns the type of the column\nfunc GetColumnType(sc *SmartContract, tableName, columnName string) (string, error) {\n\treturn sc.DbTransaction.GetColumnType(qb.GetTableName(sc.TxSmart.EcosystemID, tableName), columnName)\n}\n\n// GetType returns the name of the type of the value\nfunc GetType(val any) string {\n\tif val == nil {\n\t\treturn `nil`\n\t}\n\treturn reflect.TypeOf(val).String()\n}\n\n// StringToBytes converts string to bytes\nfunc StringToBytes(src string) []byte {\n\treturn []byte(src)\n}\n\n// BytesToString converts bytes to string\nfunc BytesToString(src []byte) string {\n\tif bytes.HasPrefix(src, BOM) && utf8.Valid(src[len(BOM):]) {\n\t\treturn string(src[len(BOM):])\n\t}\n\treturn string(src)\n}\n\n// CreateCLB allow create new CLB throught clbmanager\nfunc CreateCLB(sc *SmartContract, name, dbUser, dbPassword string, port int64) error {\n\treturn clbmanager.Manager.CreateCLB(name, dbUser, dbPassword, int(port))\n}\n\n// DeleteCLB delete clb\nfunc DeleteCLB(sc *SmartContract, name string) error {\n\treturn clbmanager.Manager.DeleteCLB(name)\n}\n\n// StartCLB run CLB process\nfunc StartCLB(sc *SmartContract, name string) error {\n\treturn clbmanager.Manager.StartCLB(name)\n}\n\n// StopCLBProcess stops CLB process\nfunc StopCLBProcess(sc *SmartContract, name string) error {\n\treturn clbmanager.Manager.StopCLB(name)\n}\n\n// GetCLBList returns list CLB process with statuses\nfunc GetCLBList(sc *SmartContract) map[string]string {\n\tlist, _ := clbmanager.Manager.ListProcessWithPorts()\n\treturn list\n}\n\nfunc GetHistoryRaw(dbTx *sqldb.DbTransaction, ecosystem int64, tableName string,\n\tid, idRollback int64) ([]any, error) {\n\ttable := qb.GetTableName(ecosystem, tableName)\n\trows, err := sqldb.GetDB(dbTx).Table(table).Where(\"id=?\", id).Rows()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"get current values\")\n\t\treturn nil, err\n\t}\n\tdefer rows.Close()\n\tif !rows.Next() {\n\t\treturn nil, errNotFound\n\t}\n\t// Get column names\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"get columns\")\n\t\treturn nil, err\n\t}\n\tvalues := make([][]byte, len(columns))\n\tscanArgs := make([]any, len(values))\n\tfor i := range values {\n\t\tscanArgs[i] = &values[i]\n\t}\n\terr = rows.Scan(scanArgs...)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"scan values\")\n\t\treturn nil, err\n\t}\n\tvar value string\n\tcurVal := types.NewMap()\n\tfor i, col := range values {\n\t\tif col == nil {\n\t\t\tvalue = \"NULL\"\n\t\t} else {\n\t\t\tvalue = string(col)\n\t\t}\n\t\tcurVal.Set(columns[i], value)\n\t}\n\tvar rollbackList []any\n\trollbackTx := &sqldb.RollbackTx{}\n\ttxs, err := rollbackTx.GetRollbackTxsByTableIDAndTableName(converter.Int64ToStr(id),\n\t\ttable, historyLimit)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"rollback history\")\n\t\treturn nil, err\n\t}\n\tfor _, tx := range *txs {\n\t\tif len(rollbackList) > 0 {\n\t\t\tprev := rollbackList[len(rollbackList)-1].(*types.Map)\n\t\t\tprev.Set(`block_id`, converter.Int64ToStr(tx.BlockID))\n\t\t\tprev.Set(`id`, converter.Int64ToStr(tx.ID))\n\t\t\tblock := sqldb.BlockChain{}\n\t\t\tif ok, err := block.Get(tx.BlockID); ok {\n\t\t\t\tprev.Set(`block_time`, time.Unix(block.Time, 0).Format(`2006-01-02 15:04:05`))\n\t\t\t} else if err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting block time\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif idRollback == tx.ID {\n\t\t\t\treturn rollbackList[len(rollbackList)-1:], nil\n\t\t\t}\n\t\t}\n\t\tif tx.Data == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\trollback := types.NewMap()\n\t\tfor _, k := range curVal.Keys() {\n\t\t\tv, _ := curVal.Get(k)\n\t\t\trollback.Set(k, v)\n\t\t}\n\t\tvar updValues map[string]any\n\t\tif err := json.Unmarshal([]byte(tx.Data), &updValues); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling rollbackTx.Data from JSON\")\n\t\t\treturn nil, err\n\t\t}\n\t\tupdMap := types.LoadMap(updValues)\n\t\tfor _, k := range updMap.Keys() {\n\t\t\tv, _ := updMap.Get(k)\n\t\t\trollback.Set(k, v)\n\t\t}\n\t\trollbackList = append(rollbackList, rollback)\n\t\tcurVal = rollback\n\t}\n\tif len(*txs) > 0 && len((*txs)[len(*txs)-1].Data) > 0 {\n\t\tprev := rollbackList[len(rollbackList)-1].(*types.Map)\n\t\tprev.Set(`block_id`, `1`)\n\t\tprev.Set(`id`, ``)\n\t\tprev.Set(`block_time`, ``)\n\t}\n\tif idRollback > 0 {\n\t\treturn []any{}, nil\n\t}\n\treturn rollbackList, nil\n}\n\nconst (\n\t// AddressLength is the expected length of the address\n\tAddressLength = 20\n)\n\ntype Address [AddressLength]byte\n\nfunc (a Address) Hex() string {\n\treturn string(a.checksumHex())\n}\n\nfunc (a *Address) checksumHex() []byte {\n\tbuf := a.hex()\n\n\t// compute checksum\n\tsha := sha3.NewLegacyKeccak256()\n\tsha.Write(buf[2:])\n\thash := sha.Sum(nil)\n\tfor i := 2; i < len(buf); i++ {\n\t\thashByte := hash[(i-2)/2]\n\t\tif i%2 == 0 {\n\t\t\thashByte = hashByte >> 4\n\t\t} else {\n\t\t\thashByte &= 0xf\n\t\t}\n\t\tif buf[i] > '9' && hashByte > 7 {\n\t\t\tbuf[i] -= 32\n\t\t}\n\t}\n\treturn buf[:]\n}\n\nfunc (a Address) hex() []byte {\n\tvar buf [len(a)*2 + 2]byte\n\tcopy(buf[:2], \"0x\")\n\thex.Encode(buf[2:], a[:])\n\treturn buf[:]\n}\n\nfunc getBtcNetParams() *chaincfg.Params {\n\tnetParams := &chaincfg.MainNetParams\n\tif syspar.IsTestMode() {\n\t\tnetParams = &chaincfg.TestNet3Params\n\t}\n\treturn netParams\n}\n\n// BitcoinLegacyAddress public key uncompressed, p2pkh address 1...\nfunc BitcoinLegacyAddress(pubKeyBytes []byte) (string, error) {\n\t// if the public key is 64 bytes, add 0x04 prefix\n\tif len(pubKeyBytes) == 64 {\n\t\tpubKeyBytes = append([]byte{0x04}, pubKeyBytes...)\n\t}\n\tpubKey, err := btcec.ParsePubKey(pubKeyBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tserializedPubKey := pubKey.SerializeUncompressed()\n\taddressPubKey, err := btcutil.NewAddressPubKey(serializedPubKey, getBtcNetParams())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\taddress := addressPubKey.EncodeAddress()\n\treturn address, nil\n}\n\n// BitcoinBip32Address bip32 path: m/32/0/{index} compressed, p2pkh address 1...\nfunc BitcoinBip32Address(pubKeyBytes []byte) (string, error) {\n\t// if the public key is 64 bytes, add 0x04 prefix\n\tif len(pubKeyBytes) == 64 {\n\t\tpubKeyBytes = append([]byte{0x04}, pubKeyBytes...)\n\t}\n\tpubKey, err := btcec.ParsePubKey(pubKeyBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tserializedPubKey := pubKey.SerializeCompressed()\n\taddressPubKey, err := btcutil.NewAddressPubKey(serializedPubKey, getBtcNetParams())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\taddress := addressPubKey.EncodeAddress()\n\treturn address, nil\n}\n\n// BitcoinBip49Address bip49 path: m/49'/0'/0'/0/{index}, segwit address p2sh 3...\nfunc BitcoinBip49Address(pubKeyBytes []byte) (string, error) {\n\t// if the public key is 64 bytes, add 0x04 prefix\n\tif len(pubKeyBytes) == 64 {\n\t\tpubKeyBytes = append([]byte{0x04}, pubKeyBytes...)\n\t}\n\tpubKey, err := btcec.ParsePubKey(pubKeyBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tserializedPubKey := pubKey.SerializeCompressed()\n\tpkHash := btcutil.Hash160(serializedPubKey)\n\twitnessProg, err := btcutil.NewAddressWitnessPubKeyHash(pkHash, getBtcNetParams())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tscript, err := txscript.PayToAddrScript(witnessProg)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\taddressScriptHash, err := btcutil.NewAddressScriptHash(script, getBtcNetParams())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\taddress := addressScriptHash.EncodeAddress()\n\treturn address, nil\n}\n\n// BitcoinBip84Address bip84 path: m/84'/0'/0'/0/{index}, segwit address p2wpkh bc1q...\nfunc BitcoinBip84Address(pubKeyBytes []byte) (string, error) {\n\t// if the public key is 64 bytes, add 0x04 prefix\n\tif len(pubKeyBytes) == 64 {\n\t\tpubKeyBytes = append([]byte{0x04}, pubKeyBytes...)\n\t}\n\tpubKey, err := btcec.ParsePubKey(pubKeyBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tserializedPubKey := pubKey.SerializeCompressed()\n\twitnessProg := btcutil.Hash160(serializedPubKey)\n\taddressWitnessPubKeyHash, err := btcutil.NewAddressWitnessPubKeyHash(witnessProg, getBtcNetParams())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\taddress := addressWitnessPubKeyHash.EncodeAddress()\n\treturn address, nil\n}\n\n// BitcoinBip86Address bip86 path: m/86'/0'/0'/0/{index},taproot address bc1p...\nfunc BitcoinBip86Address(pubKeyBytes []byte) (string, error) {\n\t// if the public key is 64 bytes, add 0x04 prefix\n\tif len(pubKeyBytes) == 64 {\n\t\tpubKeyBytes = append([]byte{0x04}, pubKeyBytes...)\n\t}\n\tpubKey, err := btcec.ParsePubKey(pubKeyBytes)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ttapKey := txscript.ComputeTaprootKeyNoScript(pubKey)\n\ttweakedPubKeyHash := schnorr.SerializePubKey(tapKey)\n\taddress, err := btcutil.NewAddressTaproot(tweakedPubKeyHash, getBtcNetParams())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ttaprootAddress := address.EncodeAddress()\n\treturn taprootAddress, nil\n}\n\n// EthereumAddress bip44 path: m/44'/60'/0'/0/{index}\n//func EthereumAddress(pubKeyBytes []byte) (string, error) {\n//\t// if the public key is 64 bytes, add 0x04 prefix\n//\tif len(pubKeyBytes) == 64 {\n//\t\tpubKeyBytes = append([]byte{0x04}, pubKeyBytes...)\n//\t}\n//\tpubKey, err := btcec.ParsePubKey(pubKeyBytes)\n//\tif err != nil {\n//\t\treturn \"\", err\n//\t}\n//\tpubKeyBytes2 := pubKey.SerializeUncompressed()[1:] // Strip off the 0x04 prefix\n//\taddress := eth_crypto.Keccak256(pubKeyBytes2)[12:] // Keccak-256 and take last 20 bytes\n//\tethAddress := \"0x\" + fmt.Sprintf(\"%x\", address)\n//\treturn ethAddress, nil\n//}\n\nfunc EthereumAddress(pub []byte) string {\n\tvar addr Address\n\tkeccak256 := &hashalgo.Keccak256{}\n\tcopy(addr[:], keccak256.GetHash(pub[:])[12:])\n\treturn addr.Hex()\n}\n\nfunc TronAddress(pub []byte) (string, error) {\n\tkeccak256 := &hashalgo.Keccak256{}\n\thash := keccak256.GetHash(pub[:])\n\thex20 := \"41\" + hex.EncodeToString(hash[len(hash)-20:])\n\treturn base58.FromHexAddress(hex20)\n}\n\nfunc GetLogTxCount(sc *SmartContract, ecosystemID int64) (int64, error) {\n\treturn sqldb.GetLogTxCount(sc.DbTransaction, ecosystemID)\n}\n\nfunc TopAmounts(sc *SmartContract, ecosystem int64, rank int64, dense bool) ([]any, error) {\n\treturn sqldb.GetTopAmounts(sc.DbTransaction, ecosystem, rank, dense)\n}\n\nfunc GetHistory(sc *SmartContract, tableName string, id int64) ([]any, error) {\n\treturn GetHistoryRaw(sc.DbTransaction, sc.TxSmart.EcosystemID, tableName, id, 0)\n}\n\nfunc GetHistoryRow(sc *SmartContract, tableName string, id, idRollback int64) (*types.Map,\n\terror) {\n\tlist, err := GetHistoryRaw(sc.DbTransaction, sc.TxSmart.EcosystemID, tableName, id, idRollback)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult := types.NewMap()\n\tif len(list) > 0 {\n\t\tfor _, key := range list[0].(*types.Map).Keys() {\n\t\t\tval, _ := list[0].(*types.Map).Get(key)\n\t\t\tresult.Set(key, val)\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc UpdateNotifications(sc *SmartContract, ecosystemID int64, accounts ...any) {\n\taccountList := make([]string, 0, len(accounts))\n\tfor i, id := range accounts {\n\t\tswitch v := id.(type) {\n\t\tcase string:\n\t\t\taccountList = append(accountList, v)\n\t\tcase []any:\n\t\t\tif i == 0 {\n\t\t\t\tUpdateNotifications(sc, ecosystemID, v...)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\tsc.Notifications.AddAccounts(ecosystemID, accountList...)\n}\n\nfunc UpdateRolesNotifications(sc *SmartContract, ecosystemID int64, roles ...any) {\n\trolesList := make([]int64, 0, len(roles))\n\tfor i, roleID := range roles {\n\t\tswitch v := roleID.(type) {\n\t\tcase int64:\n\t\t\trolesList = append(rolesList, v)\n\t\tcase string:\n\t\t\trolesList = append(rolesList, converter.StrToInt64(v))\n\t\tcase []any:\n\t\t\tif i == 0 {\n\t\t\t\tUpdateRolesNotifications(sc, ecosystemID, v...)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\tsc.Notifications.AddRoles(ecosystemID, rolesList...)\n}\nfunc DelColumn(sc *SmartContract, tableName, name string) (err error) {\n\tvar (\n\t\tcount   int64\n\t\tpermout []byte\n\t)\n\tname = converter.EscapeSQL(strings.ToLower(name))\n\ttblname := qb.GetTableName(sc.TxSmart.EcosystemID, strings.ToLower(tableName))\n\n\tt := sqldb.Table{}\n\tprefix := converter.Int64ToStr(sc.TxSmart.EcosystemID)\n\tt.SetTablePrefix(prefix)\n\tTableName := tblname\n\tif strings.HasPrefix(TableName, prefix) {\n\t\tTableName = TableName[len(prefix)+1:]\n\t}\n\tif err = sc.AccessTable(tblname, \"update\"); err != nil {\n\t\treturn\n\t}\n\tfound, err := t.Get(sc.DbTransaction, TableName)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting table info\")\n\t\treturn err\n\t}\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound, \"error\": err}).Error(\"not found table info\")\n\t\treturn fmt.Errorf(eTableNotFound, tblname)\n\t}\n\tcount, err = sc.DbTransaction.GetRecordsCountTx(tblname, ``)\n\tif err != nil {\n\t\treturn\n\t}\n\tif count > 0 {\n\t\treturn fmt.Errorf(eTableNotEmpty, tblname)\n\t}\n\tcolType, err := sc.DbTransaction.GetColumnType(tblname, name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(colType) == 0 {\n\t\treturn fmt.Errorf(eColumnNotExist, name)\n\t}\n\tvar perm map[string]string\n\tif err = unmarshalJSON([]byte(t.Columns), &perm, `columns from the table`); err != nil {\n\t\treturn err\n\t}\n\tif _, ok := perm[name]; !ok {\n\t\treturn fmt.Errorf(eColumnNotDeleted, name)\n\t}\n\tdelete(perm, name)\n\tpermout, err = marshalJSON(perm, `permissions to json`)\n\tif err != nil {\n\t\treturn\n\t}\n\tif err = sc.DbTransaction.AlterTableDropColumn(tblname, name); err != nil {\n\t\treturn\n\t}\n\t_, _, err = sc.update([]string{`columns`}, []any{string(permout)},\n\t\t`1_tables`, `id`, t.ID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !sc.CLB {\n\t\tif err = syspar.SysTableColType(sc.DbTransaction); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating sys table col type\")\n\t\t\treturn err\n\t\t}\n\t\tdata := map[string]string{\"name\": name, \"type\": colType}\n\t\tout, err := marshalJSON(data, `marshalling column info`)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn SysRollback(sc, SysRollData{Type: \"DeleteColumn\", TableName: tblname,\n\t\t\tData: string(out)})\n\t}\n\n\treturn\n}\n\nfunc DelTable(sc *SmartContract, tableName string) (err error) {\n\tvar (\n\t\tcount int64\n\t)\n\ttblname := qb.GetTableName(sc.TxSmart.EcosystemID, strings.ToLower(tableName))\n\n\tt := sqldb.Table{}\n\tprefix := converter.Int64ToStr(sc.TxSmart.EcosystemID)\n\tt.SetTablePrefix(prefix)\n\tTableName := tblname\n\tif strings.HasPrefix(TableName, prefix) {\n\t\tTableName = TableName[len(prefix)+1:]\n\t}\n\tif err = sc.AccessTable(tblname, \"update\"); err != nil {\n\t\treturn\n\t}\n\tfound, err := t.Get(sc.DbTransaction, TableName)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting table info\")\n\t\treturn err\n\t}\n\tif !found {\n\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound, \"error\": err}).Error(\"not found table info\")\n\t\treturn fmt.Errorf(eTableNotFound, tblname)\n\t}\n\n\tcount, err = sc.DbTransaction.GetRecordsCountTx(tblname, ``)\n\tif err != nil {\n\t\treturn\n\t}\n\tif count > 0 {\n\t\treturn fmt.Errorf(eTableNotEmpty, tblname)\n\t}\n\tif err = t.Delete(sc.DbTransaction); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting table\")\n\t\treturn err\n\t}\n\n\tif !sc.CLB {\n\t\tvar (\n\t\t\tout []byte\n\t\t)\n\t\tcols, err := sc.DbTransaction.GetAllColumnTypes(tblname)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttinfo := TableInfo{Table: &t, Columns: make(map[string]string)}\n\t\tfor _, item := range cols {\n\t\t\tif item[\"column_name\"] == `id` {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttinfo.Columns[item[\"column_name\"]] = sqldb.DataTypeToColumnType(item[\"data_type\"])\n\t\t}\n\t\tout, err = marshalJSON(tinfo, `marshalling table info`)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = syspar.SysTableColType(sc.DbTransaction); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating sys table col type\")\n\t\t\treturn err\n\t\t}\n\t\tif err = SysRollback(sc, SysRollData{Type: \"DeleteTable\", TableName: tblname, Data: string(out)}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn sc.DbTransaction.DropTable(tblname)\n}\n\nfunc FormatMoney(sc *SmartContract, exp string, digit int64) (string, error) {\n\tvar cents int64\n\tif digit != 0 {\n\t\tcents = digit\n\t} else {\n\t\tsp := &sqldb.Ecosystem{}\n\t\t_, err := sp.Get(sc.DbTransaction, sc.TxSmart.EcosystemID)\n\t\tif err != nil {\n\t\t\treturn `0`, logErrorDB(err, \"getting money_digit param\")\n\t\t}\n\t\tcents = sp.Digits\n\t}\n\treturn converter.FormatMoney(exp, int32(cents))\n}\n\nfunc PubToHex(in any) (ret string) {\n\tswitch v := in.(type) {\n\tcase string:\n\t\tret = crypto.PubToHex([]byte(v))\n\tcase []byte:\n\t\tret = crypto.PubToHex(v)\n\t}\n\treturn\n}\n\nfunc SendExternalTransaction(sc *SmartContract, uid, url, externalContract string,\n\tparams *types.Map, resultContract string) (err error) {\n\tvar (\n\t\tout, insertQuery string\n\t)\n\tif _, err := syspar.GetThisNodePosition(); err != nil {\n\t\treturn nil\n\t}\n\n\tout, err = JSONEncode(params)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlogger := sc.GetLogger()\n\tsqlBuilder := &qb.SQLQueryBuilder{\n\t\tEntry: logger,\n\t\tTable: `external_blockchain`,\n\t\tFields: []string{`value`, `uid`, `url`, `external_contract`,\n\t\t\t`result_contract`, `tx_time`},\n\t\tFieldValues: []any{out, uid, url, externalContract,\n\t\t\tresultContract, sc.Timestamp},\n\t\tKeyTableChkr: sqldb.KeyTableChecker{},\n\t}\n\tinsertQuery, err = sqlBuilder.GetSQLInsertQuery(sqldb.NextIDGetter{Tx: sc.DbTransaction})\n\tif err != nil {\n\t\treturn\n\t}\n\treturn sqldb.GetDB(sc.DbTransaction).Exec(insertQuery).Error\n}\n\nfunc IsHonorNodeKey(id int64) bool {\n\tif syspar.IsCandidateNodeMode() {\n\t\treturn true\n\t}\n\tfor _, item := range syspar.GetNodes() {\n\t\tif crypto.Address(item.PublicKey) == id {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "packages/smart/gas.go",
    "content": "package smart\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/gogo/protobuf/sortkeys\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype (\n\tFuelCategory struct {\n\t\tFuelType       FuelType\n\t\tDecimal        decimal.Decimal\n\t\tConversionRate float64\n\t\tFlag           GasPayAbleType\n\t\tArithmetic     Arithmetic\n\t}\n\tCombustion struct {\n\t\tFlag    int64\n\t\tPercent int64\n\t}\n\tPaymentInfo struct {\n\t\tTokenEco       int64\n\t\tToID           int64\n\t\tTaxesID        int64\n\t\tFromID         int64\n\t\tPaymentType    PaymentType\n\t\tFuelRate       decimal.Decimal\n\t\tFuelCategories []FuelCategory\n\t\tPayWallet      *sqldb.Key\n\t\tEcosystem      *sqldb.Ecosystem\n\t\tTaxesSize      int64\n\t\tIndirect       bool\n\t\tCombustion     *Combustion\n\t\tPenalty        bool\n\t}\n\tmultiPays []*PaymentInfo\n)\n\nfunc newCombustion(flag int64, percent int64) *Combustion {\n\tif flag <= 0 {\n\t\tflag = 1\n\t}\n\tif flag == 1 && percent < 0 {\n\t\tpercent = 0\n\t}\n\treturn &Combustion{Flag: flag, Percent: percent}\n}\n\nfunc NewFuelCategory(fuelType FuelType, decimal decimal.Decimal, flag GasPayAbleType, convert float64) FuelCategory {\n\tf := new(FuelCategory)\n\tf.writeFuelType(fuelType)\n\tf.writeDecimal(decimal)\n\tf.writeFlag(flag)\n\tf.writeConversionRate(convert)\n\treturn *f\n}\n\nfunc (f *FuelCategory) writeFuelType(fuelType FuelType)      { f.FuelType = fuelType }\nfunc (f *FuelCategory) writeDecimal(decimal decimal.Decimal) { f.Decimal = decimal }\nfunc (f *FuelCategory) writeArithmetic(a Arithmetic)         { f.Arithmetic = a }\nfunc (f *FuelCategory) resetArithmetic()                     { f.Arithmetic = Arithmetic_NATIVE }\nfunc (f *FuelCategory) writeFlag(tf GasPayAbleType) {\n\tif tf == GasPayAbleType_Invalid {\n\t\ttf = GasPayAbleType_Capable\n\t}\n\tf.Flag = tf\n}\n\nfunc (f *FuelCategory) writeConversionRate(cr float64) {\n\tif cr > 0 {\n\t\tf.ConversionRate = cr\n\t\treturn\n\t}\n\tf.ConversionRate = 100\n}\n\nfunc (f *FuelCategory) Detail() (string, any) {\n\treturn f.FuelType.String(), f.FeesInfo()\n}\n\nfunc (f *FuelCategory) FeesInfo() any {\n\tdetail := types.NewMap()\n\tdetail.Set(\"decimal\", f.Decimal)\n\tdetail.Set(\"value\", f.Fees())\n\tdetail.Set(\"conversion_rate\", f.ConversionRate)\n\tdetail.Set(\"flag\", f.Flag)\n\tdetail.Set(\"arithmetic\", f.Arithmetic.String())\n\tb, _ := JSONEncode(detail)\n\ts, _ := JSONDecode(b)\n\treturn s\n}\n\nfunc (f *FuelCategory) Fees() decimal.Decimal {\n\tvar value decimal.Decimal\n\tswitch f.Arithmetic {\n\tcase Arithmetic_NATIVE:\n\t\tvalue = f.Decimal\n\tcase Arithmetic_MUL:\n\t\tvalue = f.Decimal.Mul(decimal.NewFromFloat(f.ConversionRate).Div(decimal.NewFromFloat(100)))\n\tcase Arithmetic_DIV:\n\t\tvalue = f.Decimal.Div(decimal.NewFromFloat(f.ConversionRate).Div(decimal.NewFromFloat(100)))\n\tdefault:\n\t\tvalue = f.Decimal\n\t}\n\treturn value.Floor()\n}\n\nfunc (c Combustion) Fees(sum decimal.Decimal) decimal.Decimal {\n\treturn sum.Mul(decimal.NewFromInt(c.Percent)).Div(decimal.New(100, 0)).Floor()\n}\n\nfunc (c Combustion) Detail(sum decimal.Decimal) any {\n\tdetail := types.NewMap()\n\tcombustion := c.Fees(sum)\n\tdetail.Set(\"flag\", c.Flag)\n\tdetail.Set(\"percent\", c.Percent)\n\tdetail.Set(\"before\", sum)\n\tdetail.Set(\"value\", combustion)\n\tdetail.Set(\"after\", sum.Sub(combustion))\n\tb, _ := JSONEncode(detail)\n\ts, _ := JSONDecode(b)\n\treturn s\n}\n\nfunc (pay *PaymentInfo) PushFuelCategories(fes ...FuelCategory) {\n\tpay.FuelCategories = append(pay.FuelCategories, fes...)\n}\n\nfunc (pay *PaymentInfo) SetDecimalByType(fuelType FuelType, decimal decimal.Decimal) {\n\tfor i, v := range pay.FuelCategories {\n\t\tif v.FuelType == fuelType {\n\t\t\tpay.FuelCategories[i].writeDecimal(decimal)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (pay *PaymentInfo) GetPayMoney() decimal.Decimal {\n\tvar money decimal.Decimal\n\tfor i := 0; i < len(pay.FuelCategories); i++ {\n\t\tf := pay.FuelCategories[i]\n\t\tmoney = money.Add(f.Fees())\n\t}\n\treturn money\n}\n\nfunc (pay *PaymentInfo) GetEstimate() decimal.Decimal {\n\tvar money decimal.Decimal\n\tfor i := 0; i < len(pay.FuelCategories); i++ {\n\t\tf := pay.FuelCategories[i]\n\t\tif f.FuelType == FuelType_vmCost_fee {\n\t\t\tcontinue\n\t\t}\n\t\tmoney.Add(f.Fees())\n\t}\n\treturn money\n}\n\nfunc (pay *PaymentInfo) Detail() any {\n\tdetail := types.NewMap()\n\tfor i := 0; i < len(pay.FuelCategories); i++ {\n\t\tdetail.Set(pay.FuelCategories[i].Detail())\n\t}\n\tdetail.Set(\"taxes_size\", pay.TaxesSize)\n\tdetail.Set(\"payment_type\", pay.PaymentType.String())\n\tdetail.Set(\"fuel_rate\", pay.FuelRate)\n\tdetail.Set(\"token_symbol\", pay.Ecosystem.TokenSymbol)\n\tb, _ := JSONEncode(detail)\n\ts, _ := JSONDecode(b)\n\treturn s\n}\n\nfunc (pay *PaymentInfo) DetailCombustion() any {\n\tc := pay.Combustion\n\tdetail := types.NewMap()\n\tvar money decimal.Decimal\n\tfor i := 0; i < len(pay.FuelCategories); i++ {\n\t\tf := pay.FuelCategories[i]\n\t\ts := f.Fees().Mul(decimal.NewFromInt(c.Percent)).Div(decimal.New(100, 0)).Floor()\n\t\tdetail.Set(f.FuelType.String(), s)\n\t\tmoney = money.Add(f.Fees())\n\t}\n\tif !pay.Indirect && pay.TokenEco != consts.DefaultTokenEcosystem {\n\t\tdetail.Set(\"combustion\", pay.Combustion.Detail(money))\n\t}\n\tdetail.Set(\"token_symbol\", pay.Ecosystem.TokenSymbol)\n\tdetail.Set(\"fuel_rate\", pay.FuelRate)\n\tb, _ := JSONEncode(detail)\n\ts, _ := JSONDecode(b)\n\treturn s\n}\n\nfunc (f *PaymentInfo) checkVerify(sc *SmartContract) error {\n\teco := f.TokenEco\n\tif err := sc.hasExistKeyID(eco, f.FromID); err != nil {\n\t\treturn errors.Wrapf(err, fmt.Sprintf(\"From ID %d does not exist\", f.ToID))\n\t}\n\tif err := sc.hasExistKeyID(eco, f.ToID); err != nil {\n\t\treturn errors.Wrapf(err, fmt.Sprintf(\"to ID %d does not exist\", f.ToID))\n\t}\n\tif err := sc.hasExistKeyID(eco, f.TaxesID); err != nil {\n\t\treturn errors.Wrapf(err, fmt.Sprintf(\"taxes ID %d does not exist\", f.TaxesID))\n\t}\n\tif found, err := f.PayWallet.SetTablePrefix(eco).Get(sc.DbTransaction, f.FromID); err != nil || !found {\n\t\tif err != nil {\n\t\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting wallet\")\n\t\t\treturn err\n\t\t}\n\t\terr = fmt.Errorf(eEcoKeyNotFound, converter.AddressToString(f.FromID), eco)\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.ContractError, \"error\": err}).Error(\"looking for keyid in ecosystem\")\n\t\treturn err\n\t}\n\tif f.PaymentType == PaymentType_ContractCaller &&\n\t\t!bytes.Equal(sc.Key.PublicKey, f.PayWallet.PublicKey) &&\n\t\t!bytes.Equal(sc.TxSmart.PublicKey, f.PayWallet.PublicKey) &&\n\t\tsc.TxSmart.SignedBy == 0 {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"error\": errDiffKeys}).Error(errDiffKeys)\n\t\treturn errDiffKeys\n\t}\n\testimate := f.GetEstimate()\n\tamount := f.PayWallet.CapableAmount()\n\tif amount.LessThan(estimate) {\n\t\tsp := &sqldb.Ecosystem{}\n\t\t_, err := sp.Get(sc.DbTransaction, eco)\n\t\tif err != nil {\n\t\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting ecosystem\")\n\t\t\treturn err\n\t\t}\n\t\tdifference, _ := converter.FormatMoney(estimate.Sub(amount).String(), int32(sp.Digits))\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.NoFunds, \"token_eco\": eco, \"difference\": difference}).Error(\"current balance is not enough\")\n\t\treturn fmt.Errorf(eEcoCurrentBalanceDiff, f.PayWallet.AccountID, eco, difference)\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) resetFromIDForNativePay(from int64) *PaymentInfo {\n\torigin := sc.multiPays[0]\n\tcpy := &PaymentInfo{\n\t\tTokenEco:       origin.TokenEco,\n\t\tToID:           origin.ToID,\n\t\tTaxesID:        origin.TaxesID,\n\t\tFromID:         from,\n\t\tPaymentType:    origin.PaymentType,\n\t\tFuelRate:       origin.FuelRate,\n\t\tFuelCategories: make([]FuelCategory, 0),\n\t\tEcosystem:      origin.Ecosystem,\n\t\tPayWallet:      new(sqldb.Key),\n\t\tCombustion:     origin.Combustion,\n\t\tTaxesSize:      origin.TaxesSize,\n\t}\n\treturn cpy\n}\n\nfunc (sc *SmartContract) payContract(errNeedPay bool) error {\n\tsc.Penalty = errNeedPay\n\tplaceholder := `taxes for execution of %s contract`\n\tcomment := fmt.Sprintf(placeholder, sc.TxContract.Name)\n\tstatus := pbgo.TxInvokeStatusCode_SUCCESS\n\tif errNeedPay {\n\t\tcomment = \"(error)\" + comment\n\t\tstatus = pbgo.TxInvokeStatusCode_PENALTY\n\t\tts := sqldb.TransactionStatus{}\n\t\tif err := ts.UpdatePenalty(sc.DbTransaction, sc.Hash); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i := 0; i < len(sc.multiPays); i++ {\n\t\tpay := sc.multiPays[i]\n\t\tpay.Penalty = sc.Penalty\n\t\tpay.SetDecimalByType(FuelType_vmCost_fee, sc.TxUsedCost.Mul(pay.FuelRate).Mul(decimal.New(1, int32(pay.Ecosystem.Digits-sc.multiPays[0].Ecosystem.Digits))))\n\t\tmoney := pay.GetPayMoney()\n\t\twltAmount := pay.PayWallet.CapableAmount()\n\t\tif wltAmount.Cmp(money) < 0 {\n\t\t\tif !errNeedPay {\n\t\t\t\treturn fmt.Errorf(\"%s not enough fee for taxes in ecosystem %d\", pay.PayWallet.AccountID, pay.TokenEco)\n\t\t\t}\n\t\t\tmoney = wltAmount\n\t\t}\n\t\tif pay.Indirect {\n\t\t\tif err := sc.payTaxes(pay, money, GasScenesType_Direct, comment, status); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif pay.Combustion.Flag == 2 && pay.TokenEco != consts.DefaultTokenEcosystem {\n\t\t\tcombustion := pay.Combustion.Fees(money)\n\t\t\tif err := sc.payTaxes(pay, combustion, GasScenesType_Combustion, comment, status); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tmoney = money.Sub(combustion)\n\t\t}\n\t\ttaxes := money.Mul(decimal.NewFromInt(pay.TaxesSize)).Div(decimal.New(100, 0)).Floor()\n\t\tif err := sc.payTaxes(pay, money.Sub(taxes), GasScenesType_Reward, comment, status); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := sc.payTaxes(pay, taxes, GasScenesType_Taxes, comment, status); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) accountBalanceSingle(eco, id int64) (decimal.Decimal, error) {\n\tkey := &sqldb.Key{}\n\t_, err := key.SetTablePrefix(eco).Get(sc.DbTransaction, id)\n\tif err != nil {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"token_ecosystem\": eco, \"wallet\": id}).Error(\"get key balance\")\n\t\treturn decimal.Zero, err\n\t}\n\tbalance, _ := decimal.NewFromString(key.Amount)\n\treturn balance, nil\n}\n\nfunc (sc *SmartContract) payTaxes(pay *PaymentInfo, sum decimal.Decimal, t GasScenesType, comment string, status pbgo.TxInvokeStatusCode) error {\n\tif sum.IsZero() {\n\t\treturn nil\n\t}\n\tvar toID int64\n\tswitch t {\n\tcase GasScenesType_Reward, GasScenesType_Direct:\n\t\ttoID = pay.ToID\n\tcase GasScenesType_Combustion:\n\t\ttoID = 0\n\tcase GasScenesType_Taxes:\n\t\ttoID = pay.TaxesID\n\t}\n\tif err := sc.hasExistKeyID(pay.TokenEco, toID); err != nil {\n\t\treturn err\n\t}\n\tvar (\n\t\tvalues *types.Map\n\t\tfromIDBalance,\n\t\ttoIDBalance decimal.Decimal\n\t\terr error\n\t)\n\tif pay.FromID == toID {\n\t\tif fromIDBalance, err = sc.accountBalanceSingle(pay.TokenEco, pay.FromID); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttoIDBalance = fromIDBalance\n\t} else {\n\t\tif _, _, err := sc.updateWhere(\n\t\t\t[]string{`-amount`}, []any{sum}, \"1_keys\",\n\t\t\ttypes.LoadMap(map[string]any{\n\t\t\t\t`id`:        pay.FromID,\n\t\t\t\t`ecosystem`: pay.TokenEco,\n\t\t\t})); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, _, err := sc.updateWhere(\n\t\t\t[]string{\"+amount\"}, []any{sum}, \"1_keys\",\n\t\t\ttypes.LoadMap(map[string]any{\n\t\t\t\t\"id\":        toID,\n\t\t\t\t\"ecosystem\": pay.TokenEco,\n\t\t\t})); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif fromIDBalance, err = sc.accountBalanceSingle(pay.TokenEco, pay.FromID); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif toIDBalance, err = sc.accountBalanceSingle(pay.TokenEco, toID); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvalues = types.LoadMap(map[string]any{\n\t\t\"sender_id\":         pay.FromID,\n\t\t\"sender_balance\":    fromIDBalance,\n\t\t\"recipient_id\":      toID,\n\t\t\"recipient_balance\": toIDBalance,\n\t\t\"amount\":            sum,\n\t\t\"comment\":           comment,\n\t\t\"status\":            int64(status),\n\t\t\"block_id\":          sc.BlockHeader.BlockId,\n\t\t\"txhash\":            sc.Hash,\n\t\t\"ecosystem\":         pay.TokenEco,\n\t\t\"type\":              int64(t),\n\t\t\"created_at\":        sc.Timestamp,\n\t})\n\tif t == GasScenesType_Reward || t == GasScenesType_Direct {\n\t\tvalues.Set(\"value_detail\", pay.Detail())\n\t}\n\tif t == GasScenesType_Combustion {\n\t\tvalues.Set(\"value_detail\", pay.DetailCombustion())\n\t}\n\t_, _, err = sc.insert(values.Keys(), values.Values(), `1_history`)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (sc *SmartContract) needPayment() bool {\n\treturn sc.TxSmart.EcosystemID > 0 && !sc.CLB && !syspar.IsPrivateBlockchain() && sc.payFreeContract()\n}\n\nfunc (sc *SmartContract) hasExistKeyID(eco, id int64) error {\n\tkey := &sqldb.Key{}\n\tfound, err := key.SetTablePrefix(eco).Get(sc.DbTransaction, id)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !found {\n\t\t_, _, err = DBInsert(sc, \"@1keys\", types.LoadMap(map[string]any{\n\t\t\t\"id\":        id,\n\t\t\t\"account\":   converter.IDToAddress(id),\n\t\t\t\"ecosystem\": eco,\n\t\t}))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tkeyOne := &sqldb.Key{}\n\tif foundOne, err := keyOne.SetTablePrefix(1).Get(sc.DbTransaction, id); err != nil {\n\t\treturn err\n\t} else if !foundOne {\n\t\t_, _, err = DBInsert(sc, \"@1keys\", types.LoadMap(map[string]any{\n\t\t\t\"id\":        id,\n\t\t\t\"account\":   converter.IDToAddress(id),\n\t\t\t\"ecosystem\": 1,\n\t\t}))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) getFromIdAndPayType(eco int64) (int64, PaymentType) {\n\tvar (\n\t\townerInfo   = sc.TxContract.Info().Owner\n\t\tpaymentType PaymentType\n\t\tfromID      int64\n\t)\n\n\tpaymentType = PaymentType_ContractCaller\n\tfromID = sc.TxSmart.KeyID\n\n\tif ownerInfo.WalletID != 0 {\n\t\tpaymentType = PaymentType_ContractBinder\n\t\tfromID = ownerInfo.WalletID\n\t\treturn fromID, paymentType\n\t}\n\n\tif sc.TxSmart.EcosystemID != consts.DefaultTokenEcosystem && eco != consts.DefaultTokenEcosystem {\n\t\tew := &sqldb.StateParameter{}\n\t\tif found, _ := ew.SetTablePrefix(converter.Int64ToStr(sc.TxSmart.EcosystemID)).\n\t\t\tGet(sc.DbTransaction, sqldb.EcosystemWallet); found && len(ew.Value) > 0 {\n\t\t\tecosystemWallet := converter.AddressToID(ew.Value)\n\t\t\tif ecosystemWallet != 0 {\n\t\t\t\tpaymentType = PaymentType_EcosystemAddress\n\t\t\t\tfromID = ecosystemWallet\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fromID, paymentType\n}\n\n// getChangeAddress return the payment address associated with the ecosystem\nfunc (sc *SmartContract) getChangeAddress(eco int64) ([]*PaymentInfo, error) {\n\tvar (\n\t\terr         error\n\t\tstorageFee  decimal.Decimal\n\t\texpediteFee decimal.Decimal\n\t\tpays        []*PaymentInfo\n\t\tfeeMode     *sqldb.FeeModeInfo\n\t\tcurPay      = &PaymentInfo{\n\t\t\tTokenEco:       eco,\n\t\t\tToID:           sc.BlockHeader.KeyId,\n\t\t\tPayWallet:      new(sqldb.Key),\n\t\t\tEcosystem:      new(sqldb.Ecosystem),\n\t\t\tCombustion:     new(Combustion),\n\t\t\tFuelCategories: make([]FuelCategory, 0),\n\t\t\tTaxesSize:      syspar.SysInt64(syspar.TaxesSize),\n\t\t}\n\t)\n\tif _, err = curPay.Ecosystem.Get(sc.DbTransaction, curPay.TokenEco); err != nil {\n\t\treturn nil, err\n\t}\n\tfeeMode, err = curPay.Ecosystem.FeeMode()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif feeMode == nil && eco != consts.DefaultTokenEcosystem {\n\t\treturn nil, nil\n\t}\n\n\tvar f2 float64\n\tif feeMode != nil {\n\t\tf2 = feeMode.FollowFuel\n\t}\n\tif curPay.FuelRate, err = sc.fuelRate(curPay.TokenEco, f2); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif curPay.TaxesID, err = sc.taxesWallet(curPay.TokenEco); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif expediteFee, err = expediteFeeBy(sc.TxSmart.Expedite, int32(curPay.Ecosystem.Digits)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tstorageFee = storageFeeBy(sc.TxSize, int32(curPay.Ecosystem.Digits))\n\n\tcurPay.FromID, curPay.PaymentType = sc.getFromIdAndPayType(curPay.TokenEco)\n\tif feeMode != nil && eco != consts.DefaultTokenEcosystem {\n\t\t// only eco > 1\n\t\tcurPay.Combustion = newCombustion(feeMode.Combustion.Flag, feeMode.Combustion.Percent)\n\t}\n\n\tif feeMode != nil && curPay.TokenEco != consts.DefaultTokenEcosystem {\n\t\tif curPay.PaymentType == PaymentType_ContractCaller {\n\t\t\treturn nil, nil\n\t\t}\n\t\tkeys := make([]string, 0, len(feeMode.FeeModeDetail))\n\t\tfor k := range feeMode.FeeModeDetail {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\tsort.Strings(keys)\n\t\tvar indirectBool bool\n\t\tfor i := 0; i < len(keys); i++ {\n\t\t\tk := keys[i]\n\t\t\tflag := feeMode.FeeModeDetail[k]\n\t\t\tif _, ok := FuelType_value[k]; ok && GasPayAbleType(flag.FlagToInt()) == GasPayAbleType_Capable {\n\t\t\t\tindirectBool = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !indirectBool {\n\t\t\treturn nil, nil\n\t\t}\n\t\t// indirect to reward and taxes for other eco\n\t\tindirectPay := &PaymentInfo{\n\t\t\tIndirect:       true,\n\t\t\tTokenEco:       curPay.TokenEco,\n\t\t\tEcosystem:      curPay.Ecosystem,\n\t\t\tToID:           curPay.FromID,\n\t\t\tFromID:         sc.TxSmart.KeyID,\n\t\t\tPaymentType:    PaymentType_ContractCaller,\n\t\t\tFuelRate:       curPay.FuelRate,\n\t\t\tFuelCategories: make([]FuelCategory, 0),\n\t\t\tPayWallet:      new(sqldb.Key),\n\t\t\tCombustion:     new(Combustion),\n\t\t}\n\t\t// caller to reward and taxes for platform eco\n\t\tcpyPlatCaller := sc.resetFromIDForNativePay(sc.TxSmart.KeyID)\n\t\tcpyPlatCaller.PaymentType = PaymentType_ContractCaller\n\n\t\t// indirect to reward and taxes for platform eco\n\t\tcpyPlatIndirect := sc.resetFromIDForNativePay(curPay.FromID)\n\t\tcpyPlatIndirect.PaymentType = curPay.PaymentType\n\n\t\tcurPay.FromID = sc.TxSmart.KeyID\n\t\tcurPay.PaymentType = PaymentType_ContractCaller\n\n\t\t// reset sc multiPays\n\t\tsc.multiPays = sc.multiPays[:0]\n\n\t\tfor i := 0; i < len(keys); i++ {\n\t\t\tk := keys[i]\n\t\t\tflag := feeMode.FeeModeDetail[k]\n\t\t\tvar categoryFee decimal.Decimal\n\t\t\tswitch k {\n\t\t\tcase FuelType_vmCost_fee.String():\n\t\t\t\tcategoryFee = decimal.NewFromInt(0)\n\t\t\tcase FuelType_storage_fee.String():\n\t\t\t\tcategoryFee = storageFee\n\t\t\tcase FuelType_expedite_fee.String():\n\t\t\t\tcategoryFee = expediteFee\n\t\t\tdefault:\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcategory := NewFuelCategory(FuelType(FuelType_value[k]), categoryFee, GasPayAbleType(flag.FlagToInt()), flag.ConversionRateToFloat())\n\n\t\t\tswitch category.Flag {\n\t\t\tcase GasPayAbleType_Unable:\n\t\t\t\tcategory.writeDecimal(category.Decimal.Shift(int32(cpyPlatCaller.Ecosystem.Digits - curPay.Ecosystem.Digits)))\n\t\t\t\tcpyPlatCaller.PushFuelCategories(category)\n\t\t\tcase GasPayAbleType_Capable:\n\t\t\t\t// exclude FuelType_expedite_fee\n\t\t\t\tif category.FuelType != FuelType_expedite_fee {\n\t\t\t\t\tcurPay.PushFuelCategories(category)\n\t\t\t\t\tcategory.writeArithmetic(Arithmetic_MUL)\n\t\t\t\t}\n\t\t\t\tindirectPay.PushFuelCategories(category)\n\t\t\t\tcategory.resetArithmetic()\n\t\t\t\tcategory.writeDecimal(category.Decimal.Shift(int32(cpyPlatIndirect.Ecosystem.Digits - curPay.Ecosystem.Digits)))\n\t\t\t\tif category.FuelType == FuelType_expedite_fee {\n\t\t\t\t\tcategory.writeDecimal(category.Decimal.Div(decimal.NewFromFloat(feeMode.FollowFuel)))\n\t\t\t\t}\n\t\t\t\tcpyPlatIndirect.PushFuelCategories(category)\n\t\t\t}\n\t\t}\n\t\tpays = append(pays, cpyPlatCaller, cpyPlatIndirect, indirectPay, curPay)\n\t\treturn pays, nil\n\t}\n\n\tcurPay.PushFuelCategories(\n\t\tNewFuelCategory(FuelType_vmCost_fee, decimal.NewFromInt(0), GasPayAbleType_Unable, 100),\n\t\tNewFuelCategory(FuelType_storage_fee, storageFee, GasPayAbleType_Unable, 100),\n\t\tNewFuelCategory(FuelType_expedite_fee, expediteFee, GasPayAbleType_Unable, 100),\n\t)\n\tpays = append(pays, curPay)\n\treturn pays, nil\n}\n\nfunc (sc *SmartContract) prepareMultiPay() error {\n\townerInfo := sc.TxContract.Info().Owner\n\tif err := sc.appendTokens(ownerInfo.TokenID, sc.TxSmart.EcosystemID); err != nil {\n\t\treturn err\n\t}\n\n\tfor i := 0; i < len(sc.getTokenEcos()); i++ {\n\t\teco := sc.getTokenEcos()[i]\n\t\tpays, err := sc.getChangeAddress(eco)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, pay := range pays {\n\t\t\tif err = pay.checkVerify(sc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tsc.multiPays = append(sc.multiPays, pays...)\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) appendTokens(nums ...int64) error {\n\tsc.TokenEcosystems = make(map[int64]any)\n\tsc.TokenEcosystems[consts.DefaultTokenEcosystem] = nil\n\n\tfor i := 0; i < len(nums); i++ {\n\t\tnum := nums[i]\n\t\tif num <= 1 {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := sc.TokenEcosystems[num]; ok {\n\t\t\tcontinue\n\t\t}\n\t\tecosystems := &sqldb.Ecosystem{}\n\t\t_, err := ecosystems.Get(sc.DbTransaction, num)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(ecosystems.TokenSymbol) <= 0 {\n\t\t\tcontinue\n\t\t}\n\t\tsc.TokenEcosystems[num] = nil\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) getTokenEcos() []int64 {\n\tvar ecos []int64\n\tfor i := range sc.TokenEcosystems {\n\t\tecos = append(ecos, i)\n\t}\n\tsortkeys.Int64s(ecos)\n\treturn ecos\n}\n\nfunc (sc *SmartContract) payFreeContract() bool {\n\tvar (\n\t\tpfca  []string\n\t\tispay bool\n\t)\n\n\tpfc := syspar.SysString(syspar.PayFreeContract)\n\tif len(pfc) > 0 {\n\t\tpfca = strings.Split(pfc, \",\")\n\t}\n\tfor _, value := range pfca {\n\t\tif strings.TrimSpace(value) == sc.TxContract.Name {\n\t\t\tispay = true\n\t\t\tbreak\n\t\t}\n\t}\n\treturn !ispay\n}\n\nfunc (sc *SmartContract) fuelRate(eco int64, followFuel float64) (decimal.Decimal, error) {\n\tvar (\n\t\tfuelRate decimal.Decimal\n\t\terr      error\n\t\tzero     = decimal.Zero\n\t)\n\tif _, ok := syspar.HasFuelRate(eco); !ok {\n\t\tfuels := make([][]string, 0)\n\t\terr = json.Unmarshal([]byte(syspar.SysString(syspar.FuelRate)), &fuels)\n\t\tif err != nil {\n\t\t\treturn zero, err\n\t\t}\n\t\tfollow, _ := decimal.NewFromString(syspar.GetFuelRate(consts.DefaultTokenEcosystem))\n\t\ttimes := decimal.NewFromFloat(followFuel)\n\t\tif times.LessThanOrEqual(zero) {\n\t\t\ttimes = decimal.New(1, 0)\n\t\t}\n\t\tfollow = follow.Mul(times)\n\n\t\tvar newFuel []string\n\t\tnewFuel = append(newFuel, strconv.FormatInt(eco, 10), follow.String())\n\t\tfuels = append(fuels, newFuel)\n\t\tfuel, err := json.Marshal(fuels)\n\t\tif err != nil {\n\t\t\treturn zero, err\n\t\t}\n\t\tsc.taxes = true\n\t\t_, err = UpdatePlatformParam(sc, syspar.FuelRate, string(fuel), \"\")\n\t\tif err != nil {\n\t\t\treturn zero, err\n\t\t}\n\t}\n\tfuelRate, err = decimal.NewFromString(syspar.GetFuelRate(eco))\n\tif err != nil {\n\t\treturn zero, err\n\t}\n\tif fuelRate.Cmp(zero) <= 0 {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.ParameterExceeded, \"token_ecosystem\": eco}).Error(\"fuel rate must be greater than 0\")\n\t\terr = fmt.Errorf(eEcoFuelRate, eco)\n\t\treturn zero, err\n\t}\n\treturn fuelRate, nil\n}\n\nfunc (sc *SmartContract) taxesWallet(eco int64) (taxesID int64, err error) {\n\tif _, ok := syspar.HasTaxesWallet(eco); !ok {\n\t\tvar taxesPub []byte\n\t\terr = sqldb.GetDB(sc.DbTransaction).Select(\"pub\").\n\t\t\tModel(&sqldb.Key{}).Where(\"id = ? AND ecosystem = 1\",\n\t\t\tsyspar.GetTaxesWallet(1)).Row().Scan(&taxesPub)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tid := PubToID(fmt.Sprintf(\"%x\", taxesPub))\n\t\tif err = sc.hasExistKeyID(eco, id); err != nil {\n\t\t\treturn\n\t\t}\n\n\t\ttaxes := make([][]string, 0)\n\t\terr = json.Unmarshal([]byte(syspar.SysString(syspar.TaxesWallet)), &taxes)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tvar newTaxes []string\n\t\tvar tax []byte\n\t\tnewTaxes = append(newTaxes, strconv.FormatInt(eco, 10), strconv.FormatInt(id, 10))\n\t\ttaxes = append(taxes, newTaxes)\n\t\ttax, err = json.Marshal(taxes)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tsc.taxes = true\n\t\t_, err = UpdatePlatformParam(sc, syspar.TaxesWallet, string(tax), \"\")\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\ttaxesID = converter.StrToInt64(syspar.GetTaxesWallet(eco))\n\tif taxesID == 0 {\n\t\terr = fmt.Errorf(\"get eco[%d] taxes wallet err\", eco)\n\t}\n\treturn\n}\n\nfunc storageFeeBy(txSize int64, digits int32) decimal.Decimal {\n\tvar (\n\t\tstorageFee decimal.Decimal\n\t\tzero       = decimal.Zero\n\t)\n\tstorageFee = decimal.NewFromInt(syspar.SysInt64(syspar.PriceTxSize)).\n\t\tMul(decimal.New(1, digits)).\n\t\tMul(decimal.NewFromInt(txSize)).\n\t\tDiv(decimal.NewFromInt(consts.ChainSize))\n\tif storageFee.LessThanOrEqual(zero) {\n\t\tstorageFee = decimal.New(1, 0)\n\t}\n\treturn storageFee\n}\n\nfunc expediteFeeBy(expedite string, digits int32) (decimal.Decimal, error) {\n\tzero := decimal.Zero\n\tif len(expedite) > 0 {\n\t\texpedite, err := decimal.NewFromString(expedite)\n\t\tif err != nil {\n\t\t\treturn zero, fmt.Errorf(\"expediteFeeBy: %s\", err)\n\t\t}\n\t\tif expedite.LessThan(zero) {\n\t\t\treturn zero, fmt.Errorf(eGreaterThan, expedite)\n\t\t}\n\t\treturn expedite.Shift(digits), nil\n\t}\n\treturn zero, nil\n}\n"
  },
  {
    "path": "packages/smart/gas.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: gas.proto\n\npackage smart\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/gogo/protobuf/proto\"\n\tmath \"math\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package\n\ntype PaymentType int32\n\nconst (\n\tPaymentType_INVALID          PaymentType = 0\n\tPaymentType_ContractCaller   PaymentType = 1\n\tPaymentType_ContractBinder   PaymentType = 2\n\tPaymentType_EcosystemAddress PaymentType = 3\n)\n\nvar PaymentType_name = map[int32]string{\n\t0: \"INVALID\",\n\t1: \"ContractCaller\",\n\t2: \"ContractBinder\",\n\t3: \"EcosystemAddress\",\n}\n\nvar PaymentType_value = map[string]int32{\n\t\"INVALID\":          0,\n\t\"ContractCaller\":   1,\n\t\"ContractBinder\":   2,\n\t\"EcosystemAddress\": 3,\n}\n\nfunc (x PaymentType) String() string {\n\treturn proto.EnumName(PaymentType_name, int32(x))\n}\n\nfunc (PaymentType) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_df176b4a803aa869, []int{0}\n}\n\ntype GasScenesType int32\n\nconst (\n\tGasScenesType_Unknown      GasScenesType = 0\n\tGasScenesType_Reward       GasScenesType = 1\n\tGasScenesType_Taxes        GasScenesType = 2\n\tGasScenesType_Direct       GasScenesType = 15\n\tGasScenesType_Combustion   GasScenesType = 16\n\tGasScenesType_TransferSelf GasScenesType = 24\n)\n\nvar GasScenesType_name = map[int32]string{\n\t0:  \"Unknown\",\n\t1:  \"Reward\",\n\t2:  \"Taxes\",\n\t15: \"Direct\",\n\t16: \"Combustion\",\n\t24: \"TransferSelf\",\n}\n\nvar GasScenesType_value = map[string]int32{\n\t\"Unknown\":      0,\n\t\"Reward\":       1,\n\t\"Taxes\":        2,\n\t\"Direct\":       15,\n\t\"Combustion\":   16,\n\t\"TransferSelf\": 24,\n}\n\nfunc (x GasScenesType) String() string {\n\treturn proto.EnumName(GasScenesType_name, int32(x))\n}\n\nfunc (GasScenesType) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_df176b4a803aa869, []int{1}\n}\n\ntype GasPayAbleType int32\n\nconst (\n\tGasPayAbleType_Invalid GasPayAbleType = 0\n\tGasPayAbleType_Unable  GasPayAbleType = 1\n\tGasPayAbleType_Capable GasPayAbleType = 2\n)\n\nvar GasPayAbleType_name = map[int32]string{\n\t0: \"Invalid\",\n\t1: \"Unable\",\n\t2: \"Capable\",\n}\n\nvar GasPayAbleType_value = map[string]int32{\n\t\"Invalid\": 0,\n\t\"Unable\":  1,\n\t\"Capable\": 2,\n}\n\nfunc (x GasPayAbleType) String() string {\n\treturn proto.EnumName(GasPayAbleType_name, int32(x))\n}\n\nfunc (GasPayAbleType) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_df176b4a803aa869, []int{2}\n}\n\ntype FuelType int32\n\nconst (\n\tFuelType_UNKNOWN      FuelType = 0\n\tFuelType_vmCost_fee   FuelType = 1\n\tFuelType_storage_fee  FuelType = 2\n\tFuelType_expedite_fee FuelType = 3\n)\n\nvar FuelType_name = map[int32]string{\n\t0: \"UNKNOWN\",\n\t1: \"vmCost_fee\",\n\t2: \"storage_fee\",\n\t3: \"expedite_fee\",\n}\n\nvar FuelType_value = map[string]int32{\n\t\"UNKNOWN\":      0,\n\t\"vmCost_fee\":   1,\n\t\"storage_fee\":  2,\n\t\"expedite_fee\": 3,\n}\n\nfunc (x FuelType) String() string {\n\treturn proto.EnumName(FuelType_name, int32(x))\n}\n\nfunc (FuelType) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_df176b4a803aa869, []int{3}\n}\n\ntype Arithmetic int32\n\nconst (\n\tArithmetic_NATIVE Arithmetic = 0\n\tArithmetic_MUL    Arithmetic = 3\n\tArithmetic_DIV    Arithmetic = 4\n)\n\nvar Arithmetic_name = map[int32]string{\n\t0: \"NATIVE\",\n\t3: \"MUL\",\n\t4: \"DIV\",\n}\n\nvar Arithmetic_value = map[string]int32{\n\t\"NATIVE\": 0,\n\t\"MUL\":    3,\n\t\"DIV\":    4,\n}\n\nfunc (x Arithmetic) String() string {\n\treturn proto.EnumName(Arithmetic_name, int32(x))\n}\n\nfunc (Arithmetic) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_df176b4a803aa869, []int{4}\n}\n\nfunc init() {\n\tproto.RegisterEnum(\"smart.PaymentType\", PaymentType_name, PaymentType_value)\n\tproto.RegisterEnum(\"smart.GasScenesType\", GasScenesType_name, GasScenesType_value)\n\tproto.RegisterEnum(\"smart.GasPayAbleType\", GasPayAbleType_name, GasPayAbleType_value)\n\tproto.RegisterEnum(\"smart.FuelType\", FuelType_name, FuelType_value)\n\tproto.RegisterEnum(\"smart.Arithmetic\", Arithmetic_name, Arithmetic_value)\n}\n\nfunc init() { proto.RegisterFile(\"gas.proto\", fileDescriptor_df176b4a803aa869) }\n\nvar fileDescriptor_df176b4a803aa869 = []byte{\n\t// 385 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x91, 0xc1, 0x6e, 0xd3, 0x40,\n\t0x10, 0x86, 0xed, 0x84, 0xb6, 0x74, 0x02, 0xe9, 0x68, 0xc5, 0x81, 0x93, 0xef, 0x58, 0x6a, 0x73,\n\t0x40, 0xe2, 0xee, 0x38, 0xa5, 0x32, 0x14, 0x53, 0xd1, 0x24, 0x54, 0x5c, 0xd0, 0xd8, 0x9e, 0xb8,\n\t0xab, 0xda, 0xbb, 0xd6, 0xee, 0xa6, 0x8d, 0xdf, 0x82, 0xc7, 0xe2, 0xd8, 0x23, 0x47, 0x94, 0xbc,\n\t0x08, 0xb2, 0x2b, 0xa2, 0xde, 0x76, 0xbf, 0xd1, 0xcc, 0xff, 0x49, 0x3f, 0x1c, 0x97, 0x64, 0xcf,\n\t0x1a, 0xa3, 0x9d, 0x16, 0x07, 0xb6, 0x26, 0xe3, 0xc2, 0x1b, 0x18, 0x5d, 0x51, 0x5b, 0xb3, 0x72,\n\t0xf3, 0xb6, 0x61, 0x31, 0x82, 0xa3, 0x24, 0x5d, 0x46, 0x97, 0xc9, 0x0c, 0x3d, 0x21, 0x60, 0x1c,\n\t0x6b, 0xe5, 0x0c, 0xe5, 0x2e, 0xa6, 0xaa, 0x62, 0x83, 0xfe, 0x73, 0x36, 0x95, 0xaa, 0x60, 0x83,\n\t0x03, 0xf1, 0x06, 0xf0, 0x3c, 0xd7, 0xb6, 0xb5, 0x8e, 0xeb, 0xa8, 0x28, 0x0c, 0x5b, 0x8b, 0xc3,\n\t0x90, 0xe0, 0xf5, 0x05, 0xd9, 0xeb, 0x9c, 0x15, 0xdb, 0xff, 0xb7, 0x17, 0xea, 0x4e, 0xe9, 0x07,\n\t0x85, 0x9e, 0x00, 0x38, 0xfc, 0xc6, 0x0f, 0x64, 0x0a, 0xf4, 0xc5, 0x31, 0x1c, 0xcc, 0x69, 0xc3,\n\t0x16, 0x07, 0x1d, 0x9e, 0x49, 0xc3, 0xb9, 0xc3, 0x13, 0x31, 0x06, 0x88, 0x75, 0x9d, 0xad, 0xad,\n\t0x93, 0x5a, 0x21, 0x0a, 0x84, 0x57, 0x73, 0x43, 0xca, 0xae, 0xd8, 0x5c, 0x73, 0xb5, 0xc2, 0xb7,\n\t0xe1, 0x07, 0x18, 0x5f, 0x90, 0xbd, 0xa2, 0x36, 0xca, 0x2a, 0xde, 0xfb, 0xab, 0x7b, 0xaa, 0x64,\n\t0xf1, 0x94, 0xb1, 0x50, 0x94, 0x55, 0x8c, 0x7e, 0x37, 0x88, 0xa9, 0xe9, 0x3f, 0x83, 0xf0, 0x13,\n\t0xbc, 0xfc, 0xb8, 0xe6, 0x6a, 0x6f, 0x95, 0x7e, 0x4e, 0xbf, 0x7e, 0x4f, 0xd1, 0xeb, 0x22, 0xef,\n\t0xeb, 0x58, 0x5b, 0xf7, 0x73, 0xc5, 0xdd, 0xd6, 0x09, 0x8c, 0xac, 0xd3, 0x86, 0x4a, 0xee, 0xc1,\n\t0xa0, 0x73, 0xe0, 0x4d, 0xc3, 0x85, 0x74, 0x4f, 0x64, 0x18, 0x86, 0x00, 0x91, 0x91, 0xee, 0xb6,\n\t0x66, 0x27, 0xf3, 0x2e, 0x32, 0x8d, 0xe6, 0xc9, 0xf2, 0x1c, 0x3d, 0x71, 0x04, 0xc3, 0x2f, 0x8b,\n\t0x4b, 0x1c, 0x76, 0x8f, 0x59, 0xb2, 0xc4, 0x17, 0xd3, 0xf8, 0xf7, 0x36, 0xf0, 0x1f, 0xb7, 0x81,\n\t0xff, 0x77, 0x1b, 0xf8, 0xbf, 0x76, 0x81, 0xf7, 0xb8, 0x0b, 0xbc, 0x3f, 0xbb, 0xc0, 0xfb, 0xf1,\n\t0xae, 0x94, 0xee, 0x76, 0x9d, 0x9d, 0xe5, 0xba, 0x9e, 0x24, 0xd3, 0xe8, 0xe6, 0x54, 0xea, 0x49,\n\t0xa9, 0x4f, 0x65, 0x46, 0x9b, 0x49, 0x43, 0xf9, 0x1d, 0x95, 0x6c, 0x27, 0x7d, 0x63, 0xd9, 0x61,\n\t0xdf, 0xdf, 0xfb, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x62, 0xf6, 0x93, 0xcc, 0x01, 0x00,\n\t0x00,\n}\n"
  },
  {
    "path": "packages/smart/math.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"github.com/shopspring/decimal\"\n\t\"math\"\n\t\"strconv\"\n)\n\nfunc parseFloat(x any) (float64, error) {\n\tvar (\n\t\tfx  float64\n\t\terr error\n\t)\n\tswitch v := x.(type) {\n\tcase float64:\n\t\tfx = v\n\tcase int64:\n\t\tfx = float64(v)\n\tcase string:\n\t\tif fx, err = strconv.ParseFloat(v, 64); err != nil {\n\t\t\treturn 0, errFloat\n\t\t}\n\tdefault:\n\t\treturn 0, errFloat\n\t}\n\treturn fx, nil\n}\n\nfunc isValidFloat(x float64) bool {\n\treturn !(math.IsNaN(x) || math.IsInf(x, 1) || math.IsInf(x, -1))\n}\n\n// Floor returns the greatest integer value less than or equal to x\nfunc Floor(x any) (int64, error) {\n\tfx, err := parseFloat(x)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif fx = math.Floor(fx); isValidFloat(fx) {\n\t\treturn int64(fx), nil\n\t}\n\treturn 0, errFloatResult\n}\n\n// Log returns the natural logarithm of x\nfunc Log(x any) (float64, error) {\n\tfx, err := parseFloat(x)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif fx = math.Log(fx); isValidFloat(fx) {\n\t\treturn fx, nil\n\t}\n\treturn 0, errFloatResult\n}\n\n// Log10 returns the decimal logarithm of x\nfunc Log10(x any) (float64, error) {\n\tfx, err := parseFloat(x)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif fx = math.Log10(fx); isValidFloat(fx) {\n\t\treturn fx, nil\n\t}\n\treturn 0, errFloatResult\n}\n\n// Pow returns x**y, the base-x exponential of y\nfunc Pow(x, y any) (float64, error) {\n\tfx, err := parseFloat(x)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tfy, err := parseFloat(y)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif fx = math.Pow(fx, fy); isValidFloat(fx) {\n\t\treturn fx, nil\n\t}\n\treturn 0, errFloatResult\n}\n\n// Round returns the nearest integer, rounding half away from zero\nfunc Round(x any) (int64, error) {\n\tfx, err := parseFloat(x)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif fx = math.Round(fx); isValidFloat(fx) {\n\t\treturn int64(fx), nil\n\t}\n\treturn 0, errFloatResult\n}\n\n// Sqrt returns the square root of x\nfunc Sqrt(x any) (float64, error) {\n\tfx, err := parseFloat(x)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif fx = math.Sqrt(fx); isValidFloat(fx) {\n\t\treturn fx, nil\n\t}\n\treturn 0, errFloatResult\n}\n\nfunc SqrtDecimal(str string) decimal.Decimal {\n\ty, _ := decimal.NewFromString(str)\n\n\tvar z decimal.Decimal\n\tvar three = decimal.NewFromInt(3)\n\tvar two = decimal.NewFromInt(2)\n\tvar one = decimal.NewFromInt(1)\n\tif y.GreaterThan(three) {\n\t\tz = y\n\t\tx := y.Div(two).Add(one)\n\t\tfor x.LessThan(z) {\n\t\t\tz = x\n\t\t\tx = (y.Div(x).Add(x)).Div(two)\n\t\t}\n\t} else if !y.IsZero() {\n\t\tz = one\n\t}\n\treturn z\n}\n\nfunc Div(str1 string, str2 string) string {\n\tx, _ := decimal.NewFromString(str1)\n\ty, _ := decimal.NewFromString(str2)\n\treturn x.Div(y).String()\n}\n\nfunc GreaterThan(str1 string, str2 string) bool {\n\tx, _ := decimal.NewFromString(str1)\n\ty, _ := decimal.NewFromString(str2)\n\n\treturn x.GreaterThan(y)\n}\n\nfunc GreaterThanOrEqual(str1 string, str2 string) bool {\n\tx, _ := decimal.NewFromString(str1)\n\ty, _ := decimal.NewFromString(str2)\n\n\treturn x.GreaterThanOrEqual(y)\n}\n\nfunc LessThan(str1 string, str2 string) bool {\n\tx, _ := decimal.NewFromString(str1)\n\ty, _ := decimal.NewFromString(str2)\n\n\treturn x.LessThan(y)\n}\n\nfunc LessThanOrEqual(str1 string, str2 string) bool {\n\tx, _ := decimal.NewFromString(str1)\n\ty, _ := decimal.NewFromString(str2)\n\n\treturn x.LessThanOrEqual(y)\n}\n"
  },
  {
    "path": "packages/smart/selective.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb/querycost\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc addRollback(sc *SmartContract, table, tableID, rollbackInfoStr, rollDataHashStr string) {\n\trollbackTx := &types.RollbackTx{\n\t\tBlockId:   sc.BlockHeader.BlockId,\n\t\tTxHash:    sc.Hash,\n\t\tNameTable: table,\n\t\tTableId:   tableID,\n\t\tData:      rollbackInfoStr,\n\t\tDataHash:  crypto.Hash([]byte(rollDataHashStr)),\n\t}\n\tsc.RollBackTx = append(sc.RollBackTx, rollbackTx)\n}\n\nfunc (sc *SmartContract) selectiveLoggingAndUpd(fields []string, ivalues []any,\n\ttable string, inWhere *types.Map, generalRollback bool, exists bool) (int64, string, error) {\n\n\tvar (\n\t\tcost    int64\n\t\tlogData map[string]string\n\t\trows    *sqldb.OneRow\n\t)\n\tlogger := sc.GetLogger()\n\tif generalRollback && sc.BlockHeader == nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"Block is undefined\")\n\t\treturn 0, ``, fmt.Errorf(`it is impossible to write to DB when Block is undefined`)\n\t}\n\tfor i, field := range fields {\n\t\tfields[i] = strings.ToLower(field)\n\t}\n\tsqlBuilder := &qb.SQLQueryBuilder{\n\t\tEntry:        logger,\n\t\tTable:        table,\n\t\tFields:       fields,\n\t\tFieldValues:  ivalues,\n\t\tWhere:        inWhere,\n\t\tTxEcoID:      sc.TxSmart.EcosystemID,\n\t\tKeyTableChkr: sqldb.KeyTableChecker{},\n\t}\n\n\tqueryCoster := querycost.GetQueryCoster(querycost.FormulaQueryCosterType)\n\tif exists {\n\t\tselectQuery, err := sqlBuilder.GetSelectExpr()\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Error(\"on getting sql select statement\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\n\t\tselectCost, err := queryCoster.QueryCost(sc.DbTransaction, selectQuery)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table, \"query\": selectQuery, \"fields\": fields, \"values\": ivalues, \"where\": inWhere}).Error(\"getting query total cost\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\t\trows = sc.DbTransaction.GetOneRowTransaction(selectQuery)\n\t\tlogData, err = rows.String()\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"query\": selectQuery}).Error(\"getting one row transaction\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\t\tcost += selectCost\n\t\tif len(logData) == 0 {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound, \"err\": errUpdNotExistRecord, \"table\": table, \"fields\": fields, \"values\": shortString(fmt.Sprintf(\"%+v\", ivalues), 100), \"where\": inWhere, \"query\": shortString(selectQuery, 100)}).Error(\"updating for not existing record\")\n\t\t\treturn 0, \"\", errUpdNotExistRecord\n\t\t}\n\t\tif sqlBuilder.IsEmptyWhere() {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.NotFound,\n\t\t\t\t\"error\": errWhereUpdate}).Error(\"update without where\")\n\t\t\treturn 0, \"\", errWhereUpdate\n\t\t}\n\t}\n\tvar rollDataHashStr string\n\n\tif !sqlBuilder.Where.IsEmpty() && len(logData) > 0 {\n\t\tupdateExpr, err := sqlBuilder.GetSQLUpdateExpr(logData)\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Error(\"on getting update expression for update\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\n\t\twhereExpr, err := sqlBuilder.GetSQLWhereExpr()\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Error(\"on getting where expression for update\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\t\tif !sc.CLB {\n\t\t\tupdateQuery := `UPDATE \"` + sqlBuilder.Table + `\" SET ` + updateExpr + \" \" + whereExpr\n\t\t\tupdateCost, err := queryCoster.QueryCost(sc.DbTransaction, updateQuery)\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"query\": updateQuery}).Error(\"getting query total cost for update query\")\n\t\t\t\treturn 0, \"\", err\n\t\t\t}\n\t\t\tcost += updateCost\n\t\t}\n\t\trollDataHashStr = `UPDATE \"` + strings.Trim(sqlBuilder.Table, `\"`) + `\" SET ` + updateExpr + \" \" + whereExpr\n\t\terr = sc.DbTransaction.Update(sqlBuilder.Table, updateExpr, whereExpr)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": sqlBuilder.Table, \"update\": updateExpr, \"where\": whereExpr}).Error(\"getting update query\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\n\t\tfor i := 0; i < len(rows.List) && generalRollback; i++ {\n\t\t\trollData := rows.List[i]\n\t\t\trollbackInfoStr, err := sqlBuilder.GenerateRollBackInfoString(rollData)\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithError(err).Error(\"on generate rollback info string for update\")\n\t\t\t\treturn 0, \"\", err\n\t\t\t}\n\t\t\taddRollback(sc, sqlBuilder.Table, rollData[\"id\"], rollbackInfoStr, rollDataHashStr)\n\t\t}\n\n\t\tvar ids []string\n\t\tfor _, result := range rows.List {\n\t\t\tif len(result[\"id\"]) > 0 {\n\t\t\t\tids = append(ids, result[\"id\"])\n\t\t\t}\n\t\t}\n\t\tif len(ids) == 1 {\n\t\t\tsqlBuilder.SetTableID(ids[0])\n\t\t} else {\n\t\t\tsqlBuilder.SetTableID(strings.Join(ids, \",\"))\n\t\t}\n\t\treturn cost, sqlBuilder.TableID(), nil\n\t}\n\n\tinsertQuery, err := sqlBuilder.GetSQLInsertQuery(sqldb.NextIDGetter{Tx: sc.DbTransaction})\n\tif err != nil {\n\t\tlogger.WithError(err).Error(\"on build insert query\")\n\t\treturn 0, \"\", err\n\t}\n\n\t\tinsertCost, err := queryCoster.QueryCost(sc.DbTransaction, insertQuery)\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"query\": insertQuery}).Error(\"getting total query cost for insert query\")\n\t\t\treturn 0, \"\", err\n\t\t}\n\t\trollDataHashStr = insertQuery\n\tcost += insertCost\n\terr = sc.DbTransaction.ExecSql(insertQuery)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"query\": insertQuery}).Error(\"executing insert query\")\n\t\treturn 0, \"\", err\n\t}\n\n\tif generalRollback {\n\t\tvar tid string\n\t\ttid = sqlBuilder.TableID()\n\t\tidNames := strings.SplitN(sqlBuilder.Table, `_`, 2)\n\t\tif len(idNames) == 2 {\n\t\t\tif sqlBuilder.KeyTableChkr.IsKeyTable(idNames[1]) {\n\t\t\t\ttid = sqlBuilder.TableID() + \",\" + sqlBuilder.GetEcosystem()\n\t\t\t}\n\t\t}\n\t\taddRollback(sc, sqlBuilder.Table, tid, \"\", rollDataHashStr)\n\t}\n\treturn cost, sqlBuilder.TableID(), nil\n}\n\nfunc (sc *SmartContract) insert(fields []string, ivalues []any,\n\ttable string) (int64, string, error) {\n\treturn sc.selectiveLoggingAndUpd(fields, ivalues, table, nil, !sc.CLB && sc.Rollback, false)\n}\n\nfunc (sc *SmartContract) updateWhere(fields []string, values []any,\n\ttable string, where *types.Map) (int64, string, error) {\n\treturn sc.selectiveLoggingAndUpd(fields, values, table, where, !sc.CLB && sc.Rollback, true)\n}\n\nfunc (sc *SmartContract) update(fields []string, values []any,\n\ttable string, whereField string, whereValue any) (int64, string, error) {\n\treturn sc.updateWhere(fields, values, table, types.LoadMap(map[string]any{\n\t\twhereField: fmt.Sprint(whereValue)}))\n}\n\nfunc shortString(raw string, length int) string {\n\tif len(raw) > length {\n\t\treturn raw[:length]\n\t}\n\n\treturn raw\n}\n"
  },
  {
    "path": "packages/smart/smart.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage smart\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sort\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\t// MaxPrice is a maximal value that price function can return\n\tMaxPrice = 100000000000000000\n)\n\nconst (\n\tCallDelayedContract = \"@1CallDelayedContract\"\n\tNewUserContract     = \"@1NewUser\"\n\tNewBadBlockContract = \"@1NewBadBlock\"\n)\n\nvar (\n\tbuiltinContract = map[string]bool{\n\t\tCallDelayedContract: true,\n\t\tNewUserContract:     true,\n\t\tNewBadBlockContract: true,\n\t}\n)\n\n// SmartContract is storing smart contract data\ntype SmartContract struct {\n\tCLB             bool\n\tRollback        bool\n\tFullAccess      bool\n\tSysUpdate       bool\n\tVM              *script.VM\n\tTxSmart         *types.SmartTransaction\n\tTxData          map[string]any\n\tTxContract      *Contract\n\tTxFuel          int64           // The fuel of executing contract\n\tTxCost          int64           // Maximum cost of executing contract\n\tTxUsedCost      decimal.Decimal // Used cost of CPU resources\n\tTXBlockFuel     decimal.Decimal\n\tBlockHeader     *types.BlockHeader\n\tPreBlockHeader  *types.BlockHeader\n\tLoop            map[string]bool\n\tHash            []byte\n\tPayload         []byte\n\tTimestamp       int64\n\tTxSignature     []byte\n\tTxSize          int64\n\tSize            common.StorageSize\n\tPublicKeys      [][]byte\n\tDbTransaction   *sqldb.DbTransaction\n\tRand            *rand.Rand\n\tFlushRollback   []*FlushInfo\n\tNotifications   types.Notifications\n\tGenBlock        bool\n\tTimeLimit       int64\n\tKey             *sqldb.Key\n\tRollBackTx      []*types.RollbackTx\n\tmultiPays       multiPays\n\ttaxes           bool\n\tPenalty         bool\n\tTokenEcosystems map[int64]any\n\tOutputsMap      map[sqldb.KeyUTXO][]sqldb.SpentInfo\n\tTxInputsMap     map[sqldb.KeyUTXO][]sqldb.SpentInfo\n\tTxOutputsMap    map[sqldb.KeyUTXO][]sqldb.SpentInfo\n\tPrevSysPar      map[string]string\n\tEcoParams       []sqldb.EcoParam\n}\n\n// AppendStack adds an element to the stack of contract call or removes the top element when name is empty\nfunc (sc *SmartContract) AppendStack(fn string) error {\n\tif sc.isAllowStack(fn) {\n\t\tcont := sc.TxContract\n\t\tfor _, item := range cont.StackCont {\n\t\t\tif item == fn {\n\t\t\t\treturn fmt.Errorf(eContractLoop, fn)\n\t\t\t}\n\t\t}\n\t\tcont.StackCont = append(cont.StackCont, fn)\n\t\tsc.TxContract.Extend[script.Extend_stack] = cont.StackCont\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) PopStack(fn string) {\n\tif sc.isAllowStack(fn) {\n\t\tcont := sc.TxContract\n\t\tif len(cont.StackCont) > 0 {\n\t\t\tcont.StackCont = cont.StackCont[:len(cont.StackCont)-1]\n\t\t\tsc.TxContract.Extend[script.Extend_stack] = cont.StackCont\n\t\t}\n\t}\n}\n\nfunc (sc *SmartContract) isAllowStack(fn string) bool {\n\t// Stack contains only contracts\n\tc := VMGetContract(sc.VM, fn, uint32(sc.TxSmart.EcosystemID))\n\treturn c != nil\n}\n\nfunc InitVM() {\n\tscript.GetVM().SetExtendCost(getCost)\n\tscript.GetVM().SetFuncCallsDB(funcCallsDBP)\n\tscript.GetVM().Extend(&script.ExtendData{\n\t\tObjects: EmbedFuncs(defineVMType()), AutoPars: map[string]string{\n\t\t\t`*smart.SmartContract`: `sc`,\n\t\t},\n\t\tWriteFuncs: writeFuncs,\n\t})\n}\n\nfunc defineVMType() script.VMType {\n\tif conf.Config.IsCLB() {\n\t\treturn script.VMType_CLB\n\t}\n\tif conf.Config.IsCLBMaster() {\n\t\treturn script.VMType_CLBMaster\n\t}\n\treturn script.VMType_Smart\n}\n\n// GetLogger is returning logger\nfunc (sc *SmartContract) GetLogger() *log.Entry {\n\tvar name string\n\tif sc.TxContract != nil {\n\t\tname = sc.TxContract.Name\n\t}\n\treturn log.WithFields(log.Fields{\"tx\": fmt.Sprintf(\"%x\", sc.Hash), \"clb\": sc.CLB, \"name\": name, \"tx_eco\": sc.TxSmart.EcosystemID})\n}\n\nfunc GetAllContracts() (string, error) {\n\tvar ret []string\n\tfor k := range script.GetVM().Objects {\n\t\tret = append(ret, k)\n\t}\n\n\tsort.Strings(ret)\n\tresultByte, err := json.Marshal(ret)\n\tresult := string(resultByte)\n\treturn result, err\n}\n\n// ActivateContract sets Active status of the contract in script.GetVM()\nfunc ActivateContract(tblid, state int64, active bool) {\n\tfor i, item := range script.GetVM().CodeBlock.Children {\n\t\tif item != nil && item.Type == script.ObjectType_Contract {\n\t\t\tcinfo := item.GetContractInfo()\n\t\t\tif cinfo.Owner.TableID == tblid && cinfo.Owner.StateID == uint32(state) {\n\t\t\t\tscript.GetVM().Children[i].GetContractInfo().Owner.Active = active\n\t\t\t}\n\t\t}\n\t}\n}\n\n// SetContractWallet changes WalletID of the contract in script.GetVM()\nfunc SetContractWallet(sc *SmartContract, tblid, state int64, wallet int64) error {\n\tif err := validateAccess(sc, \"SetContractWallet\"); err != nil {\n\t\treturn err\n\t}\n\tfor i, item := range script.GetVM().CodeBlock.Children {\n\t\tif item != nil && item.Type == script.ObjectType_Contract {\n\t\t\tcinfo := item.GetContractInfo()\n\t\t\tif cinfo.Owner.TableID == tblid && cinfo.Owner.StateID == uint32(state) {\n\t\t\t\tscript.GetVM().Children[i].GetContractInfo().Owner.WalletID = wallet\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) getExtend() map[string]any {\n\tvar block, blockTime, blockKeyID, blockNodePosition int64\n\tvar perBlockHash string\n\tif sc.BlockHeader != nil {\n\t\tblock = sc.BlockHeader.BlockId\n\t\tblockKeyID = sc.BlockHeader.KeyId\n\t\tblockTime = sc.BlockHeader.Timestamp\n\t\tblockNodePosition = sc.BlockHeader.NodePosition\n\t}\n\tif sc.PreBlockHeader != nil {\n\t\tperBlockHash = hex.EncodeToString(sc.PreBlockHeader.BlockHash)\n\t}\n\thead := sc.TxSmart\n\textend := map[string]any{\n\t\tscript.Extend_type:          head.ID,\n\t\tscript.Extend_time:          sc.Timestamp,\n\t\tscript.Extend_ecosystem_id:  head.EcosystemID,\n\t\tscript.Extend_node_position: blockNodePosition,\n\t\tscript.Extend_block:         block,\n\t\tscript.Extend_key_id:        sc.Key.ID,\n\t\tscript.Extend_account_id:    sc.Key.AccountID,\n\t\tscript.Extend_block_key_id:  blockKeyID,\n\t\tscript.Extend_parent:        ``,\n\t\tscript.Extend_txcost:        sc.GetContractLimit(),\n\t\tscript.Extend_txhash:        sc.Hash,\n\t\t//script.Extend_result:              ``,\n\t\tscript.Extend_sc:                  sc,\n\t\tscript.Extend_contract:            sc.TxContract,\n\t\tscript.Extend_block_time:          blockTime,\n\t\tscript.Extend_original_contract:   ``,\n\t\tscript.Extend_this_contract:       ``,\n\t\tscript.Extend_guest_key:           consts.GuestKey,\n\t\tscript.Extend_guest_account:       consts.GuestAddress,\n\t\tscript.Extend_black_hole_key:      converter.HoleAddrMap[converter.BlackHoleAddr].K,\n\t\tscript.Extend_black_hole_account:  converter.HoleAddrMap[converter.BlackHoleAddr].S,\n\t\tscript.Extend_white_hole_key:      converter.HoleAddrMap[converter.WhiteHoleAddr].K,\n\t\tscript.Extend_white_hole_account:  converter.HoleAddrMap[converter.WhiteHoleAddr].S,\n\t\tscript.Extend_pre_block_data_hash: perBlockHash,\n\t\tscript.Extend_gen_block:           sc.GenBlock,\n\t\tscript.Extend_time_limit:          sc.TimeLimit,\n\t}\n\tfor key, val := range sc.TxData {\n\t\textend[key] = val\n\t}\n\n\treturn extend\n}\n\nfunc PrefixName(table string) (prefix, name string) {\n\tname = table\n\tif off := strings.IndexByte(table, '_'); off > 0 && table[0] >= '0' && table[0] <= '9' {\n\t\tprefix = table[:off]\n\t\tname = table[off+1:]\n\t}\n\treturn\n}\n\nfunc (sc *SmartContract) IsCustomTable(table string) (isCustom bool, err error) {\n\tprefix, name := PrefixName(table)\n\tif len(prefix) > 0 {\n\t\ttables := &sqldb.Table{}\n\t\ttables.SetTablePrefix(prefix)\n\t\tfound, err := tables.Get(sc.DbTransaction, name)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif found {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\nfunc (sc *SmartContract) AccessTablePerm(table, action string) (map[string]string, error) {\n\tvar (\n\t\terr             error\n\t\ttablePermission map[string]string\n\t)\n\tlogger := sc.GetLogger()\n\tisRead := action == `read`\n\tif qb.GetTableName(sc.TxSmart.EcosystemID, table) == `1_parameters` || qb.GetTableName(sc.TxSmart.EcosystemID, table) == `1_app_params` {\n\t\tif isRead || sc.TxSmart.KeyID == converter.StrToInt64(EcosysParam(sc, `founder_account`)) {\n\t\t\treturn tablePermission, nil\n\t\t}\n\t\tlogger.WithFields(log.Fields{\"type\": consts.AccessDenied}).Error(\"Access denied\")\n\t\treturn tablePermission, errAccessDenied\n\t}\n\n\tif isCustom, err := sc.IsCustomTable(table); err != nil {\n\t\tlogger.WithFields(log.Fields{\"table\": table, \"error\": err, \"type\": consts.DBError}).Error(\"checking custom table\")\n\t\treturn tablePermission, err\n\t} else if !isCustom {\n\t\tif isRead {\n\t\t\treturn tablePermission, nil\n\t\t}\n\t\treturn tablePermission, fmt.Errorf(eNotCustomTable, table)\n\t}\n\n\tprefix, name := PrefixName(table)\n\ttables := &sqldb.Table{}\n\ttables.SetTablePrefix(prefix)\n\ttablePermission, err = tables.GetPermissions(sc.DbTransaction, name, \"\")\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting table permissions\")\n\t\treturn tablePermission, err\n\t}\n\tif len(tablePermission[action]) > 0 {\n\t\tret, err := sc.EvalIf(tablePermission[action])\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"table\": table, \"action\": action, \"permissions\": tablePermission[action], \"error\": err, \"type\": consts.EvalError}).Error(\"evaluating table permissions for action\")\n\t\t\treturn tablePermission, err\n\t\t}\n\t\tif !ret {\n\t\t\tlogger.WithFields(log.Fields{\"table\": table, \"action\": action, \"permissions\": tablePermission[action], \"type\": consts.EvalError}).Error(\"access denied\")\n\t\t\treturn tablePermission, fmt.Errorf(\"table: %w\", errAccessDenied)\n\t\t}\n\t}\n\treturn tablePermission, nil\n}\n\n// AccessTable checks the access right to the table\nfunc (sc *SmartContract) AccessTable(table, action string) error {\n\tif sc.FullAccess {\n\t\treturn nil\n\t}\n\t_, err := sc.AccessTablePerm(table, action)\n\treturn err\n}\n\nfunc getPermColumns(input string) (perm permColumn, err error) {\n\tif strings.HasPrefix(input, `{`) {\n\t\terr = unmarshalJSON([]byte(input), &perm, `on perm columns`)\n\t} else {\n\t\tperm.Update = input\n\t}\n\treturn\n}\n\n// AccessColumns checks access rights to the columns\nfunc (sc *SmartContract) AccessColumns(table string, columns *[]string, update bool) error {\n\tlogger := sc.GetLogger()\n\tif sc.FullAccess {\n\t\treturn nil\n\t}\n\tif qb.GetTableName(sc.TxSmart.EcosystemID, table) == `1_parameters` || qb.GetTableName(sc.TxSmart.EcosystemID, table) == `1_app_params` {\n\t\tif update {\n\t\t\tif sc.TxSmart.KeyID == converter.StrToInt64(EcosysParam(sc, `founder_account`)) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tlog.WithFields(log.Fields{\"txSmart.KeyId\": sc.TxSmart.KeyID}).Error(\"ACCESS DENIED\")\n\t\t\treturn errAccessDenied\n\t\t}\n\t\treturn nil\n\t}\n\tprefix, name := PrefixName(table)\n\ttables := &sqldb.Table{}\n\ttables.SetTablePrefix(prefix)\n\tfound, err := tables.Get(sc.DbTransaction, name)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting table columns\")\n\t\treturn err\n\t}\n\tif !found {\n\t\tif !update {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(eTableNotFound, table)\n\t}\n\tvar cols map[string]string\n\terr = json.Unmarshal([]byte(tables.Columns), &cols)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"getting table columns\")\n\t\treturn err\n\t}\n\tcolNames := make([]string, 0, len(*columns))\n\tfor _, col := range *columns {\n\t\tif col == `*` {\n\t\t\tfor column := range cols {\n\t\t\t\tcolNames = append(colNames, column)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tcolNames = append(colNames, col)\n\t}\n\n\tcolList := make([]string, len(colNames))\n\tfor i, col := range colNames {\n\t\tcolname := converter.Sanitize(col, `->`)\n\t\tif strings.Contains(colname, `->`) {\n\t\t\tcolname = colname[:strings.Index(colname, `->`)]\n\t\t}\n\t\tcolList[i] = colname\n\t}\n\tchecked := make(map[string]bool)\n\tvar notaccess bool\n\tfor i, name := range colList {\n\t\tif status, ok := checked[name]; ok {\n\t\t\tif !status {\n\t\t\t\tcolList[i] = ``\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tcond := cols[name]\n\t\tif len(cond) > 0 {\n\t\t\tperm, err := getPermColumns(cond)\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithFields(log.Fields{\"type\": consts.InvalidObject, \"error\": err}).Error(\"getting access columns\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif update {\n\t\t\t\tcond = perm.Update\n\t\t\t} else {\n\t\t\t\tcond = perm.Read\n\t\t\t}\n\t\t\tif len(cond) > 0 {\n\t\t\t\tret, err := sc.EvalIf(cond)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.WithFields(log.Fields{\"condition\": cond, \"column\": name,\n\t\t\t\t\t\t\"type\": consts.EvalError}).Error(\"evaluating condition\")\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tchecked[name] = ret\n\t\t\t\tif !ret {\n\t\t\t\t\tif update {\n\t\t\t\t\t\tlogger.WithFields(log.Fields{\"table\": table, \"column\": name, \"condition\": cond, \"type\": consts.EvalError}).Error(\"access denied\")\n\t\t\t\t\t\treturn fmt.Errorf(\"column: %w\", errAccessDenied)\n\t\t\t\t\t}\n\t\t\t\t\tcolList[i] = ``\n\t\t\t\t\tnotaccess = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif !update && notaccess {\n\t\tretColumn := make([]string, 0)\n\t\tfor i, val := range colList {\n\t\t\tif val != `` {\n\t\t\t\tretColumn = append(retColumn, colNames[i])\n\t\t\t}\n\t\t}\n\t\tif len(retColumn) == 0 {\n\t\t\treturn errAccessDenied\n\t\t}\n\t\t*columns = retColumn\n\t}\n\treturn nil\n}\n\nfunc (sc *SmartContract) CheckAccess(tableName, columns string, ecosystem int64) (table string, perm map[string]string,\n\tcols string, err error) {\n\tvar collist []string\n\n\ttable = converter.ParseTable(tableName, ecosystem)\n\tcollist, err = qb.GetColumns(columns)\n\tif err != nil {\n\t\treturn\n\t}\n\tif !syspar.IsPrivateBlockchain() {\n\t\tcols = PrepareColumns(collist)\n\t\treturn\n\t}\n\tperm, err = sc.AccessTablePerm(table, `read`)\n\tif err != nil {\n\t\treturn\n\t}\n\tif err = sc.AccessColumns(table, &collist, false); err != nil {\n\t\treturn\n\t}\n\tcols = PrepareColumns(collist)\n\treturn\n}\n\n// AccessRights checks the access right by executing the condition value\nfunc (sc *SmartContract) AccessRights(condition string, iscondition bool) error {\n\tsp := &sqldb.StateParameter{}\n\tprefix := converter.Int64ToStr(sc.TxSmart.EcosystemID)\n\n\tsp.SetTablePrefix(prefix)\n\t_, err := sp.Get(sc.DbTransaction, condition)\n\tif err != nil {\n\t\treturn err\n\t}\n\tconditions := sp.Value\n\tif iscondition {\n\t\tconditions = sp.Conditions\n\t}\n\tif len(conditions) > 0 {\n\t\tret, err := sc.EvalIf(conditions)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !ret {\n\t\t\treturn errAccessDenied\n\t\t}\n\t} else {\n\t\treturn fmt.Errorf(eNotCondition, condition)\n\t}\n\treturn nil\n}\n\n// EvalIf counts and returns the logical value of the specified expression\nfunc (sc *SmartContract) EvalIf(conditions string) (bool, error) {\n\treturn sc.VM.EvalIf(conditions, uint32(sc.TxSmart.EcosystemID), sc.getExtend())\n}\n\n// GetContractLimit returns the default maximal cost of contract\nfunc (sc *SmartContract) GetContractLimit() (ret int64) {\n\t// default maximum cost of F\n\tif len(sc.TxSmart.MaxSum) > 0 {\n\t\tsc.TxCost = converter.StrToInt64(sc.TxSmart.MaxSum)\n\t} else {\n\t\tsc.TxCost = syspar.GetMaxCost()\n\t}\n\treturn sc.TxCost\n}\n\nfunc (sc *SmartContract) GetSignedBy(public []byte) (int64, error) {\n\tsignedBy := sc.TxSmart.KeyID\n\tif sc.TxSmart.SignedBy != 0 {\n\t\tvar isNode bool\n\t\tsignedBy = sc.TxSmart.SignedBy\n\t\tif syspar.IsCandidateNodeMode() {\n\t\t\treturn signedBy, nil\n\t\t}\n\t\thonorNodes := syspar.GetNodes()\n\t\tdelay := sqldb.DelayedContract{}\n\t\tif ok, _ := delay.GetByContract(sc.DbTransaction, sc.TxContract.Name); !ok && !builtinContract[sc.TxContract.Name] {\n\t\t\treturn 0, fmt.Errorf(\"%w: %v\", errDelayedContract, sc.TxContract.Name)\n\t\t}\n\t\tif len(honorNodes) > 0 {\n\t\t\tfor _, node := range honorNodes {\n\t\t\t\tif crypto.Address(node.PublicKey) == signedBy {\n\t\t\t\t\tisNode = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tisNode = crypto.Address(syspar.GetNodePubKey()) == signedBy\n\t\t}\n\n\t\tif sc.TxContract.Name == NewUserContract && !isNode {\n\t\t\treturn signedBy, nil\n\t\t}\n\t\tif !isNode {\n\t\t\treturn 0, errDelayedContract\n\t\t}\n\t} else if len(public) > 0 && sc.TxSmart.KeyID != crypto.Address(public) {\n\t\treturn 0, errDiffKeys\n\t}\n\treturn signedBy, nil\n}\n\n// CallContract calls the contract functions according to the specified flags\nfunc (sc *SmartContract) CallContract(point string) (string, error) {\n\tvar (\n\t\tresult string\n\t\terr    error\n\t)\n\tlogger := sc.GetLogger()\n\n\tretError := func(err error) (string, error) {\n\t\teText := err.Error()\n\t\tif !strings.HasPrefix(eText, `{`) && err != script.ErrVMTimeLimit {\n\t\t\terr = script.SetVMError(`panic`, eText)\n\t\t}\n\t\treturn ``, err\n\t}\n\n\tif err = sc.checkTxSign(); err != nil {\n\t\treturn ``, err\n\t}\n\n\tneedPayment := sc.needPayment()\n\tif needPayment {\n\t\terr = sc.prepareMultiPay()\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Error(\"prepare multi\")\n\t\t\treturn ``, err\n\t\t}\n\t}\n\n\tsc.TxContract.Extend = sc.getExtend()\n\tif err = sc.AppendStack(sc.TxContract.Name); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.ContractError, \"error\": err}).Error(\"loop in contract\")\n\t\treturn retError(err)\n\t}\n\tsc.VM = script.GetVM()\n\n\tctrctExtend := sc.TxContract.Extend\n\tbefore := ctrctExtend[script.Extend_txcost].(int64)\n\ttxSizeFuel := syspar.GetSizeFuel() * sc.TxSize / 1024\n\tctrctExtend[script.Extend_txcost] = ctrctExtend[script.Extend_txcost].(int64) - txSizeFuel\n\n\t_, nameContract := converter.ParseName(sc.TxContract.Name)\n\tctrctExtend[script.Extend_original_contract] = nameContract\n\tctrctExtend[script.Extend_this_contract] = nameContract\n\n\tmethods := []string{`conditions`, `action`}\n\terr = script.RunContractById(sc.VM, int32(sc.TxSmart.ID), methods, sc.TxContract.Extend, sc.Hash)\n\tif ctrctExtend[script.Extend_txcost].(int64) < 0 {\n\t\tsc.TxFuel = before\n\t} else {\n\t\tsc.TxFuel = before - ctrctExtend[script.Extend_txcost].(int64)\n\t}\n\tsc.TxUsedCost = decimal.New(sc.TxFuel, 0)\n\n\tif err == nil {\n\t\tif ctrctExtend[script.Extend_result] != nil {\n\t\t\tresult = fmt.Sprint(ctrctExtend[script.Extend_result])\n\t\t\tif !utf8.ValidString(result) {\n\t\t\t\tresult, err = retError(errNotValidUTF)\n\t\t\t}\n\t\t\tif len(result) > 255 {\n\t\t\t\tresult = result[:255] + `...`\n\t\t\t}\n\t\t}\n\t}\nlp:\n\tif err != nil {\n\t\tsc.RollBackTx = nil\n\t\tsc.DbTransaction.BinLogSql = nil\n\t\tif errReset := sc.DbTransaction.ResetSavepoint(point); errReset != nil {\n\t\t\treturn retError(errors.Wrap(err, errReset.Error()))\n\t\t}\n\t\tif needPayment {\n\t\t\tif errPay := sc.payContract(true); errPay != nil {\n\t\t\t\tsc.RollBackTx = nil\n\t\t\t\tsc.DbTransaction.BinLogSql = nil\n\t\t\t\tif errRollsp := sc.DbTransaction.RollbackSavepoint(point); errRollsp != nil {\n\t\t\t\t\treturn retError(errors.Wrap(err, errRollsp.Error()))\n\t\t\t\t}\n\t\t\t\treturn errors.Wrap(err, errPay.Error()).Error(), nil\n\t\t\t}\n\t\t\treturn err.Error(), nil\n\t\t}\n\t\treturn retError(err)\n\t}\n\n\tif needPayment {\n\t\tif errPay := sc.payContract(false); errPay != nil {\n\t\t\terr = errPay\n\t\t\tgoto lp\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc (sc *SmartContract) checkTxSign() error {\n\tvar public []byte\n\tif len(sc.TxSmart.PublicKey) > 0 && string(sc.TxSmart.PublicKey) != `null` {\n\t\tpublic = sc.TxSmart.PublicKey\n\t}\n\tsignedBy, err := sc.GetSignedBy(public)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tisFound, err := sc.Key.SetTablePrefix(sc.TxSmart.EcosystemID).Get(sc.DbTransaction, signedBy)\n\tif err != nil {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting wallet\")\n\t\treturn err\n\t}\n\n\tif !isFound {\n\t\terr = fmt.Errorf(eEcoKeyNotFound, converter.AddressToString(signedBy), sc.TxSmart.EcosystemID)\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.ContractError, \"error\": err}).Error(\"looking for keyid\")\n\t\treturn err\n\t}\n\tif sc.Key.Disable() {\n\t\terr = fmt.Errorf(eEcoKeyDisable, converter.AddressToString(signedBy), sc.TxSmart.EcosystemID)\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.ContractError, \"error\": err}).Error(\"disable keyid\")\n\t\treturn err\n\t}\n\tif len(sc.Key.PublicKey) > 0 {\n\t\tpublic = sc.Key.PublicKey\n\t}\n\tif len(public) == 0 {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"empty public key\")\n\t\treturn errEmptyPublicKey\n\t}\n\tsc.PublicKeys = append(sc.PublicKeys, public)\n\n\tvar CheckSignResult bool\n\n\tCheckSignResult, err = utils.CheckSign(sc.PublicKeys, sc.Hash, sc.TxSignature, false)\n\tif err != nil {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"checking tx data sign\")\n\t\treturn err\n\t}\n\tif !CheckSignResult {\n\t\tsc.GetLogger().WithFields(log.Fields{\"type\": consts.InvalidObject}).Error(\"incorrect sign\")\n\t\treturn errIncorrectSign\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/smart/smart_p.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/language\"\n\t\"github.com/IBAX-io/go-ibax/packages/migration\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils/metric\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tnBindWallet          = \"BindWallet\"\n\tnUnbindWallet        = \"UnbindWallet\"\n\tnEditColumn          = \"EditColumn\"\n\tnEditContract        = \"EditContract\"\n\tnEditEcosystemName   = \"EditEcosystemName\"\n\tnEditLang            = \"EditLang\"\n\tnEditLangJoint       = \"EditLangJoint\"\n\tnEditTable           = \"EditTable\"\n\tnImport              = \"Import\"\n\tnNewColumn           = \"NewColumn\"\n\tnNewContract         = \"NewContract\"\n\tnNewEcosystem        = \"NewEcosystem\"\n\tnNewLang             = \"NewLang\"\n\tnNewLangJoint        = \"NewLangJoint\"\n\tnNewTable            = \"NewTable\"\n\tnNewTableJoint       = \"NewTableJoint\"\n\tnNewUser             = \"NewUser\"\n\tnBlockReward         = \"BlockReward\"\n\tnCallDelayedContract = \"CallDelayedContract\"\n)\n\n// SignRes contains the data of the signature\ntype SignRes struct {\n\tParam string `json:\"name\"`\n\tText  string `json:\"text\"`\n}\n\n// TxSignJSON is a structure for additional signs of transaction\ntype TxSignJSON struct {\n\tForSign string    `json:\"forsign\"`\n\tField   string    `json:\"field\"`\n\tTitle   string    `json:\"title\"`\n\tParams  []SignRes `json:\"params\"`\n}\n\nfunc getCost(name string) int64 {\n\tif price, ok := syspar.GetPriceExec(utils.ToSnakeCase(name)); ok {\n\t\treturn price\n\t}\n\treturn -1\n}\n\n// UpdatePlatformParam updates the system parameter\nfunc UpdatePlatformParam(sc *SmartContract, name, value, conditions string) (int64, error) {\n\tvar (\n\t\tfields []string\n\t\tvalues []any\n\t)\n\tpar := &sqldb.PlatformParameter{}\n\tfound, err := par.Get(sc.DbTransaction, name)\n\tif err != nil {\n\t\treturn 0, logErrorDB(err, \"system parameter get\")\n\t}\n\tif !found {\n\t\treturn 0, logErrorf(eParamNotFound, name, consts.NotFound, \"system parameter get\")\n\t}\n\tcond := par.Conditions\n\tif len(cond) > 0 && !sc.taxes {\n\t\tret, err := sc.EvalIf(cond)\n\t\tif err != nil {\n\t\t\treturn 0, logError(err, consts.EvalError, \"evaluating conditions\")\n\t\t}\n\t\tif !ret {\n\t\t\treturn 0, logErrorShort(errAccessDenied, consts.AccessDenied)\n\t\t}\n\t}\n\tif len(value) > 0 {\n\t\tvar (\n\t\t\tok, checked bool\n\t\t\tlist        [][]string\n\t\t)\n\t\tival := converter.StrToInt64(value)\n\tcheck:\n\t\tswitch name {\n\t\tcase syspar.GapsBetweenBlocks:\n\t\t\tok = ival > 0 && ival < 86400\n\t\tcase syspar.RbBlocks1,\n\t\t\tsyspar.NumberNodes:\n\t\t\tok = ival > 0 && ival < 1000\n\t\tcase syspar.TaxesSize,\n\t\t\tsyspar.PriceCreateRate,\n\t\t\tsyspar.PriceTxSize,\n\t\t\tsyspar.BlockReward:\n\t\t\tok = ival >= 0\n\t\tcase syspar.MaxBlockSize,\n\t\t\tsyspar.MaxTxSize,\n\t\t\tsyspar.MaxTxCount,\n\t\t\tsyspar.MaxColumns,\n\t\t\tsyspar.MaxIndexes,\n\t\t\tsyspar.MaxBlockUserTx,\n\t\t\tsyspar.MaxTxFuel,\n\t\t\tsyspar.MaxBlockFuel,\n\t\t\tsyspar.MaxForsignSize:\n\t\t\tok = ival > 0\n\t\tcase syspar.FuelRate,\n\t\t\tsyspar.TaxesWallet:\n\t\t\tif err := unmarshalJSON([]byte(value), &list, `system param`); err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\tfor _, item := range list {\n\t\t\t\tif len(item) != 2 || converter.StrToInt64(item[0]) <= 0 ||\n\t\t\t\t\t(name == syspar.FuelRate && converter.StrToInt64(item[1]) <= 0) ||\n\t\t\t\t\t(name == syspar.TaxesWallet && converter.StrToInt64(item[1]) == 0) {\n\t\t\t\t\tbreak check\n\t\t\t\t}\n\t\t\t}\n\t\t\tchecked = true\n\t\tcase syspar.HonorNodes:\n\t\t\tvar fnodes []*syspar.HonorNode\n\t\t\tif err := json.Unmarshal([]byte(value), &fnodes); err != nil {\n\t\t\t\tbreak check\n\t\t\t}\n\t\t\tif len(fnodes) > 1 {\n\t\t\t\tif err = syspar.DuplicateHonorNode(fnodes); err != nil {\n\t\t\t\t\treturn 0, logErrorValue(err, consts.InvalidObject, err.Error(), value)\n\t\t\t\t}\n\t\t\t}\n\t\t\tchecked = len(fnodes) > 0\n\t\tdefault:\n\t\t\tif strings.HasPrefix(name, `extend_cost_`) || strings.HasSuffix(name, `_price`) {\n\t\t\t\tok = ival >= 0\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tchecked = true\n\t\t}\n\t\tif !checked && (!ok || converter.Int64ToStr(ival) != value) {\n\t\t\treturn 0, logErrorValue(errInvalidValue, consts.InvalidObject, errInvalidValue.Error(),\n\t\t\t\tvalue)\n\t\t}\n\t\tfields = append(fields, \"value\")\n\t\tvalues = append(values, value)\n\t}\n\tif len(conditions) > 0 {\n\t\tif err := script.VMCompileEval(sc.VM, conditions, 0); err != nil {\n\t\t\treturn 0, logErrorValue(err, consts.EvalError, \"compiling eval\", conditions)\n\t\t}\n\t\tfields = append(fields, \"conditions\")\n\t\tvalues = append(values, conditions)\n\t}\n\tif len(fields) == 0 {\n\t\treturn 0, logErrorShort(errEmpty, consts.EmptyObject)\n\t}\n\t_, _, err = sc.update(fields, values, \"1_platform_parameters\", \"id\", par.ID)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\terr = syspar.SysUpdate(sc.DbTransaction)\n\tif err != nil {\n\t\treturn 0, logErrorDB(err, \"updating syspar\")\n\t}\n\tsc.SysUpdate = true\n\treturn 0, nil\n}\n\n// SysParamString returns the value of the system parameter\nfunc SysParamString(name string) string {\n\treturn syspar.SysString(name)\n}\n\n// SysParamInt returns the value of the system parameter\nfunc SysParamInt(name string) int64 {\n\treturn syspar.SysInt64(name)\n}\n\n// SysFuel returns the fuel rate\nfunc SysFuel(state int64) string {\n\treturn syspar.GetFuelRate(state)\n}\n\n// Int converts the value to a number\nfunc Int(v any) (int64, error) {\n\treturn converter.ValueToInt(v)\n}\n\n// Str converts the value to a string\nfunc Str(v any) (ret string) {\n\tif v == nil {\n\t\treturn\n\t}\n\treturn fmt.Sprintf(`%v`, v)\n}\n\n// Money converts the value into a numeric type for money\nfunc Money(v any) (decimal.Decimal, error) {\n\treturn script.ValueToDecimal(v)\n}\n\n// Float converts the value to float64\nfunc Float(v any) (ret float64) {\n\treturn script.ValueToFloat(v)\n}\n\n// Join is joining input with separator\nfunc Join(input []any, sep string) string {\n\tvar ret string\n\tfor i, item := range input {\n\t\tif i > 0 {\n\t\t\tret += sep\n\t\t}\n\t\tret += fmt.Sprintf(`%v`, item)\n\t}\n\treturn ret\n}\n\n// Split splits the input string to array\nfunc Split(input, sep string) []any {\n\tout := strings.Split(input, sep)\n\tresult := make([]any, len(out))\n\tfor i, val := range out {\n\t\tresult[i] = reflect.ValueOf(val).Interface()\n\t}\n\treturn result\n}\n\n// PubToID returns a numeric identifier for the public key specified in the hexadecimal form.\nfunc PubToID(hexkey string) int64 {\n\tpubkey, err := crypto.HexToPub(hexkey)\n\tif err != nil {\n\t\tlogErrorValue(err, consts.CryptoError, \"decoding hexkey to string\", hexkey)\n\t\treturn 0\n\t}\n\treturn crypto.Address(pubkey)\n}\n\nfunc CheckSign(pub, data, sign string) (bool, error) {\n\tpk, err := hex.DecodeString(pub)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\ts, err := hex.DecodeString(sign)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tpk = crypto.CutPub(pk)\n\treturn crypto.Verify(pk, []byte(data), s)\n}\n\nfunc CheckNumberChars(data string) bool {\n\tdat := []byte(data)\n\tdl := len(dat)\n\tfor i := 0; i < dl; i++ {\n\t\td := dat[i]\n\t\tif (d >= 0x30 && d <= 0x39) || (d >= 0x41 && d <= 0x5A) || (d >= 0x61 && d <= 0x7A) {\n\t\t} else {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// HexToBytes converts the hexadecimal representation to []byte\nfunc HexToBytes(hexdata string) ([]byte, error) {\n\treturn hex.DecodeString(hexdata)\n}\n\n// LangRes returns the language resource\nfunc LangRes(sc *SmartContract, idRes string) string {\n\tret, _ := language.LangText(sc.DbTransaction, idRes, int(sc.TxSmart.EcosystemID), sc.TxSmart.Lang)\n\treturn ret\n}\n\n// NewLang creates new language\nfunc CreateLanguage(sc *SmartContract, name, trans string) (id int64, err error) {\n\tif err := validateAccess(sc, \"CreateLanguage\"); err != nil {\n\t\treturn 0, err\n\t}\n\tidStr := converter.Int64ToStr(sc.TxSmart.EcosystemID)\n\tif err = language.UpdateLang(int(sc.TxSmart.EcosystemID), name, trans); err != nil {\n\t\treturn 0, err\n\t}\n\tif _, id, err = DBInsert(sc, `@1languages`, types.LoadMap(map[string]any{\"name\": name,\n\t\t\"ecosystem\": idStr, \"res\": trans})); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"inserting new language\")\n\t\treturn 0, err\n\t}\n\treturn id, nil\n}\n\n// EditLanguage edits language\nfunc EditLanguage(sc *SmartContract, id int64, name, trans string) error {\n\tif err := validateAccess(sc, \"EditLanguage\"); err != nil {\n\t\treturn err\n\t}\n\tif err := language.UpdateLang(int(sc.TxSmart.EcosystemID), name, trans); err != nil {\n\t\treturn err\n\t}\n\tif _, err := DBUpdate(sc, `@1languages`, id,\n\t\ttypes.LoadMap(map[string]any{\"name\": name, \"res\": trans})); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"inserting new language\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// GetContractByName returns id of the contract with this name\nfunc GetContractByName(sc *SmartContract, name string) int64 {\n\tcontract := VMGetContract(sc.VM, name, uint32(sc.TxSmart.EcosystemID))\n\tif contract == nil {\n\t\treturn 0\n\t}\n\tinfo := contract.Info()\n\tif info == nil {\n\t\treturn 0\n\t}\n\n\treturn info.Owner.TableID\n}\n\n// GetContractById returns the name of the contract with this id\nfunc GetContractById(sc *SmartContract, id int64) string {\n\t_, ret, err := DBSelect(sc, \"contracts\", \"value\", id, `id`, 0, 1, nil, \"\", \"\", false)\n\tif err != nil || len(ret) != 1 {\n\t\tlogErrorDB(err, \"getting contract name\")\n\t\treturn ``\n\t}\n\n\tre := regexp.MustCompile(`(?is)^\\s*contract\\s+([\\d\\w_]+)\\s*{`)\n\tvar val string\n\tif v, found := ret[0].(*types.Map).Get(\"value\"); found {\n\t\tval = v.(string)\n\t}\n\tnames := re.FindStringSubmatch(val)\n\tif len(names) != 2 {\n\t\treturn ``\n\t}\n\treturn names[1]\n}\n\n// EvalCondition gets the condition and check it\nfunc EvalCondition(sc *SmartContract, table, name, condfield string) error {\n\ttableName := converter.ParseTable(table, sc.TxSmart.EcosystemID)\n\tquery := `SELECT ` + converter.EscapeName(condfield) + ` FROM \"` + tableName + `\" WHERE name = ? and ecosystem = ?`\n\tconditions, err := sc.DbTransaction.Single(query, name, sc.TxSmart.EcosystemID).String()\n\tif err != nil {\n\t\treturn logErrorDB(err, \"executing single query\")\n\t}\n\tif len(conditions) == 0 {\n\t\treturn logErrorfShort(eRecordNotFound, name, consts.NotFound)\n\t}\n\treturn Eval(sc, conditions)\n}\n\n// Replace replaces old substrings to new substrings\nfunc Replace(s, old, new string) string {\n\treturn strings.Replace(s, old, new, -1)\n}\n\n// CreateEcosystem creates a new ecosystem\nfunc CreateEcosystem(sc *SmartContract, wallet int64, name string) (int64, error) {\n\tif err := validateAccess(sc, \"CreateEcosystem\"); err != nil {\n\t\treturn 0, err\n\t}\n\n\tvar sp sqldb.StateParameter\n\tsp.SetTablePrefix(`1`)\n\tfound, err := sp.Get(sc.DbTransaction, `founder_account`)\n\tif err != nil {\n\t\treturn 0, logErrorDB(err, \"getting founder\")\n\t}\n\n\tif !found || len(sp.Value) == 0 {\n\t\treturn 0, logErrorShort(errFounderAccount, consts.NotFound)\n\t}\n\n\tid, err := sc.DbTransaction.GetNextID(\"1_ecosystems\")\n\tif err != nil {\n\t\treturn 0, logErrorDB(err, \"generating next ecosystem id\")\n\t}\n\n\tappID, err := sc.DbTransaction.GetNextID(\"1_applications\")\n\tif err != nil {\n\t\treturn 0, logErrorDB(err, \"generating next application id\")\n\t}\n\n\tif err = sqldb.ExecSchemaEcosystem(sc.DbTransaction,\n\t\tmigration.SqlData{\n\t\t\tEcosystem: int(id),\n\t\t\tWallet:    wallet,\n\t\t\tName:      name,\n\t\t\tFounder:   converter.StrToInt64(sp.Value),\n\t\t\tAppID:     appID,\n\t\t\tAccount:   converter.AddressToString(wallet),\n\t\t}); err != nil {\n\t\treturn 0, logErrorDB(err, \"executing ecosystem schema\")\n\t}\n\n\tidStr := converter.Int64ToStr(id)\n\tif err := LoadContract(sc.DbTransaction, id); err != nil {\n\t\treturn 0, err\n\t}\n\tif !sc.CLB {\n\t\tif err := SysRollback(sc, SysRollData{Type: \"NewEcosystem\", ID: id}); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\tsc.FullAccess = true\n\n\tif _, _, err = DBInsert(sc, \"@1parameters\", types.LoadMap(map[string]any{\n\t\t\"name\": \"ecosystem_wallet\", \"value\": \"0\", \"conditions\": `ContractConditions(\"DeveloperCondition\")`,\n\t\t\"ecosystem\": idStr,\n\t})); err != nil {\n\t\treturn 0, logErrorDB(err, \"inserting system parameter\")\n\t}\n\n\tif _, _, err = DBInsert(sc, \"@1applications\", types.LoadMap(map[string]any{\n\t\t\"name\":       \"System\",\n\t\t\"conditions\": `ContractConditions(\"MainCondition\")`,\n\t\t\"ecosystem\":  id,\n\t})); err != nil {\n\t\treturn 0, logErrorDB(err, \"inserting application\")\n\t}\n\tif _, _, err = DBInsert(sc, `@1pages`, types.LoadMap(map[string]any{\"ecosystem\": idStr,\n\t\t\"name\": \"default_page\", \"app_id\": appID, \"value\": SysParamString(\"default_ecosystem_page\"),\n\t\t\"menu\": \"default_menu\", \"conditions\": `ContractConditions(\"DeveloperCondition\")`})); err != nil {\n\t\treturn 0, logErrorDB(err, \"inserting default page\")\n\t}\n\tif _, _, err = DBInsert(sc, `@1menu`, types.LoadMap(map[string]any{\"ecosystem\": idStr,\n\t\t\"name\": \"default_menu\", \"value\": SysParamString(\"default_ecosystem_menu\"), \"title\": \"default\", \"conditions\": `ContractConditions(\"DeveloperCondition\")`})); err != nil {\n\t\treturn 0, logErrorDB(err, \"inserting default menu\")\n\t}\n\n\tvar (\n\t\tret []any\n\t\tpub string\n\t)\n\t_, ret, err = DBSelect(sc, \"@1keys\", \"pub\", wallet, `id`, 0, 1, nil, \"\", \"\", false)\n\tif err != nil {\n\t\treturn 0, logErrorDB(err, \"getting pub key\")\n\t}\n\n\tif Len(ret) > 0 {\n\t\tif v, found := ret[0].(*types.Map).Get(\"pub\"); found {\n\t\t\tpub = v.(string)\n\t\t}\n\t}\n\tif _, _, err := DBInsert(sc, `@1keys`, types.LoadMap(map[string]any{\n\t\t\"id\":        wallet,\n\t\t\"account\":   converter.AddressToString(wallet),\n\t\t\"pub\":       pub,\n\t\t\"ecosystem\": idStr,\n\t})); err != nil {\n\t\treturn 0, logErrorDB(err, \"inserting key\")\n\t}\n\n\tsc.FullAccess = false\n\t// because of we need to know which ecosystem to rollback.\n\t// All tables will be deleted so it's no need to rollback data from tables\n\tif _, _, err := DBInsert(sc, \"@1ecosystems\", types.LoadMap(map[string]any{\n\t\t\"id\":   id,\n\t\t\"name\": name,\n\t})); err != nil {\n\t\treturn 0, logErrorDB(err, \"insert new ecosystem to stat table\")\n\t}\n\treturn id, err\n}\n\n// EditEcosysName set newName for ecosystem\nfunc EditEcosysName(sc *SmartContract, sysID int64, newName string) error {\n\tif err := validateAccess(sc, \"EditEcosysName\"); err != nil {\n\t\treturn err\n\t}\n\n\t_, err := DBUpdate(sc, \"@1ecosystems\", sysID,\n\t\ttypes.LoadMap(map[string]any{\"name\": newName}))\n\treturn err\n}\n\n// Size returns the length of the string\nfunc Size(s string) int64 {\n\treturn int64(len(s))\n}\n\n// Substr returns the substring of the string\nfunc Substr(s string, off int64, slen int64) string {\n\tilen := int64(len(s))\n\tif off < 0 || slen < 0 || off > ilen {\n\t\treturn ``\n\t}\n\tif off+slen > ilen {\n\t\treturn s[off:]\n\t}\n\treturn s[off : off+slen]\n}\n\n// BndWallet sets wallet_id to current wallet and updates value in vm\nfunc BndWallet(sc *SmartContract, tblid int64, state int64) error {\n\tif err := validateAccess(sc, \"BindWallet\"); err != nil {\n\t\tlog.Error(\"BindWallet access denied\")\n\t\treturn err\n\t}\n\n\tif _, _, err := sc.update([]string{\"wallet_id\"}, []any{sc.TxSmart.KeyID}, \"1_contracts\", \"id\", tblid); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"contract_id\": tblid}).Error(\"on updating contract wallet\")\n\t\treturn err\n\t}\n\n\treturn SetContractWallet(sc, tblid, state, sc.TxSmart.KeyID)\n}\n\n// UnbndWallet sets Active status of the contract in smartVM\nfunc UnbndWallet(sc *SmartContract, tblid int64, state int64) error {\n\tif err := validateAccess(sc, \"UnbindWallet\"); err != nil {\n\t\treturn err\n\t}\n\n\tif _, _, err := sc.update([]string{\"wallet_id\"}, []any{0}, \"1_contracts\", \"id\", tblid); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"contract_id\": tblid}).Error(\"on updating contract wallet\")\n\t\treturn err\n\t}\n\n\treturn SetContractWallet(sc, tblid, state, 0)\n}\n\n// CheckSignature checks the additional signatures for the contract\nfunc CheckSignature(sc *SmartContract, i map[string]any, name string) error {\n\tstate, name := converter.ParseName(name)\n\tsn := sqldb.Signature{}\n\tsn.SetTablePrefix(converter.Int64ToStr(int64(state)))\n\t_, err := sn.Get(name)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"executing single query\")\n\t}\n\tif len(sn.Value) == 0 {\n\t\treturn nil\n\t}\n\thexsign, err := hex.DecodeString(i[`Signature`].(string))\n\tif len(hexsign) == 0 || err != nil {\n\t\treturn logError(errWrongSignature, consts.ConversionError, \"converting signature to hex\")\n\t}\n\n\tvar sign TxSignJSON\n\tif err = unmarshalJSON([]byte(sn.Value), &sign, `unmarshalling sign`); err != nil {\n\t\treturn err\n\t}\n\twallet := i[`key_id`].(int64)\n\tforsign := fmt.Sprintf(`%d,%d`, uint64(i[`time`].(int64)), uint64(wallet))\n\tfor _, isign := range sign.Params {\n\t\tval := i[isign.Param]\n\t\tif val == nil {\n\t\t\tval = ``\n\t\t}\n\t\tforsign += fmt.Sprintf(`,%v`, val)\n\t}\n\n\tCheckSignResult, err := utils.CheckSign(sc.PublicKeys, []byte(forsign), hexsign, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !CheckSignResult {\n\t\treturn logErrorfShort(eIncorrectSignature, forsign, consts.InvalidObject)\n\t}\n\treturn nil\n}\n\n// DBSelectMetrics returns list of metrics by name and time interval\nfunc DBSelectMetrics(sc *SmartContract, metric, timeInterval, aggregateFunc string) ([]any, error) {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn nil, ErrNotImplementedOnCLB\n\t}\n\n\ttimeBlock := time.Unix(sc.Timestamp, 0).Format(`2006-01-02 15:04:05`)\n\tresult, err := sqldb.GetMetricValues(metric, timeInterval, aggregateFunc, timeBlock)\n\tif err != nil {\n\t\treturn nil, logErrorDB(err, \"get values of metric\")\n\t}\n\treturn result, nil\n}\n\n// DBCollectMetrics returns actual values of all metrics\n// This function used to further store these values\nfunc DBCollectMetrics(sc *SmartContract) []any {\n\tif conf.Config.IsSupportingCLB() {\n\t\treturn nil\n\t}\n\n\tc := metric.NewCollector(\n\t\tmetric.CollectMetricDataForEcosystemTables,\n\t\tmetric.CollectMetricDataForEcosystemTx,\n\t)\n\treturn c.Values(sc.Timestamp)\n}\n\n// JSONDecode converts json string to object\nfunc JSONDecode(input string) (ret any, err error) {\n\terr = unmarshalJSON([]byte(input), &ret, \"unmarshalling json\")\n\tret = types.ConvertMap(ret)\n\treturn\n}\n\n// JSONEncodeIndent converts object to json string\nfunc JSONEncodeIndent(input any, indent string) (string, error) {\n\trv := reflect.ValueOf(input)\n\tif rv.Kind() == reflect.Ptr {\n\t\trv = rv.Elem()\n\t}\n\tif rv.Kind() == reflect.Struct && reflect.TypeOf(input).String() != `*types.Map` {\n\t\treturn \"\", logErrorfShort(eTypeJSON, input, consts.TypeError)\n\t}\n\tvar (\n\t\tb   []byte\n\t\terr error\n\t)\n\tif len(indent) == 0 {\n\t\tb, err = json.Marshal(input)\n\t} else {\n\t\tb, err = json.MarshalIndent(input, ``, indent)\n\t}\n\tif err != nil {\n\t\treturn ``, logError(err, consts.JSONMarshallError, `marshalling json`)\n\t}\n\tout := string(b)\n\tout = strings.Replace(out, `\\u003c`, `<`, -1)\n\tout = strings.Replace(out, `\\u003e`, `>`, -1)\n\tout = strings.Replace(out, `\\u0026`, `&`, -1)\n\treturn out, nil\n}\n\n// JSONEncode converts object to json string\nfunc JSONEncode(input any) (string, error) {\n\treturn JSONEncodeIndent(input, ``)\n}\n\n// Append syn for golang 'append' function\nfunc Append(slice []any, val any) []any {\n\treturn append(slice, val)\n}\n\nfunc HasSlice(element any, slice any) bool {\n\ts := reflect.ValueOf(slice)\n\tif s.Kind() != reflect.Slice {\n\t\treturn false\n\t}\n\tfor i := 0; i < s.Len(); i++ {\n\t\tif reflect.DeepEqual(element, s.Index(i).Interface()) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// RegexpMatch validates regexp\nfunc RegexpMatch(str, reg string) bool {\n\tif strings.Contains(reg, `\\u`) || strings.Contains(reg, `\\U`) {\n\t\tvar err error\n\t\treg, err = strconv.Unquote(`\"` + reg + `\"`)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t}\n\tre := regexp.MustCompile(reg)\n\treturn re.MatchString(str)\n}\n\nfunc DBCount(sc *SmartContract, tableName string, inWhere *types.Map) (count int64, err error) {\n\ttblname := qb.GetTableName(sc.TxSmart.EcosystemID, tableName)\n\twhere, err := qb.GetWhere(inWhere)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\terr = sqldb.GetDB(sc.DbTransaction).Table(tblname).Where(where).Count(&count).Error\n\treturn\n}\n\nfunc MathMod(x, y float64) float64 {\n\treturn math.Mod(x, y)\n}\n\nfunc MathModDecimal(x, y decimal.Decimal) decimal.Decimal {\n\treturn x.Mod(y)\n}\nfunc TransferSelf(sc *SmartContract, value string, source string, target string) (flag bool, err error) {\n\tfromID := sc.TxSmart.KeyID\n\toutputsMap := sc.OutputsMap\n\ttxInputsMap := sc.TxInputsMap\n\ttxOutputsMap := sc.TxOutputsMap\n\t//txHash := sc.Hash\n\tecosystem := sc.TxSmart.EcosystemID\n\tblockId := sc.BlockHeader.BlockId\n\t//dbTx := sc.DbTransaction\n\tkeyUTXO := sqldb.KeyUTXO{Ecosystem: ecosystem, KeyId: fromID}\n\t//sum, _ := decimal.NewFromString(value)\n\tpayValue, _ := decimal.NewFromString(value)\n\tstatus := pbgo.TxInvokeStatusCode_SUCCESS\n\tvar values *types.Map\n\tvar balance decimal.Decimal\n\tif strings.EqualFold(\"UTXO\", source) && strings.EqualFold(\"Account\", target) {\n\n\t\ttxInputs := sqldb.GetUnusedOutputsMap(keyUTXO, outputsMap)\n\n\t\tif len(txInputs) == 0 {\n\t\t\treturn false, fmt.Errorf(eEcoCurrentBalance, converter.IDToAddress(fromID), ecosystem)\n\t\t}\n\n\t\ttotalAmount := decimal.Zero\n\t\tfor _, input := range txInputs {\n\t\t\toutputValue, _ := decimal.NewFromString(input.OutputValue)\n\t\t\ttotalAmount = totalAmount.Add(outputValue)\n\t\t}\n\n\t\tif totalAmount.GreaterThanOrEqual(payValue) && payValue.GreaterThan(decimal.Zero) {\n\t\t\tflag = true // The transfer was successful\n\t\t\t//txOutputs = append(txOutputs, sqldb.SpentInfo{OutputKeyId: toID, OutputValue: value, BlockId: blockId, Ecosystem: ecosystem})\n\t\t\ttotalAmount = totalAmount.Sub(payValue)\n\t\t\tif _, _, err := sc.updateWhere([]string{\"+amount\"}, []any{payValue}, \"1_keys\", types.LoadMap(map[string]any{\"id\": fromID, \"ecosystem\": ecosystem})); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tif balance, err = sc.accountBalanceSingle(ecosystem, fromID); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn false, fmt.Errorf(eEcoCurrentBalance, converter.IDToAddress(fromID), ecosystem)\n\t\t}\n\n\t\t// The change\n\t\tvar txOutputs []sqldb.SpentInfo\n\t\tif totalAmount.GreaterThan(decimal.Zero) {\n\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: 0, OutputKeyId: fromID, OutputValue: totalAmount.String(), BlockId: blockId, Ecosystem: ecosystem, Type: consts.UTXO_Type_Self_UTXO}) // The change\n\t\t}\n\t\tif len(txInputs) > 0 {\n\t\t\tsqldb.PutAllOutputsMap(txInputs, txInputsMap)\n\t\t}\n\t\tif len(txOutputs) > 0 {\n\t\t\tsqldb.PutAllOutputsMap(txOutputs, txOutputsMap)\n\t\t}\n\t\tvalues = types.LoadMap(map[string]any{\n\t\t\t\"sender_id\":         fromID,\n\t\t\t\"sender_balance\":    balance,\n\t\t\t\"recipient_id\":      fromID,\n\t\t\t\"recipient_balance\": balance,\n\t\t\t\"amount\":            payValue,\n\t\t\t\"comment\":           source,\n\t\t\t\"status\":            int64(status),\n\t\t\t\"block_id\":          sc.BlockHeader.BlockId,\n\t\t\t\"txhash\":            sc.Hash,\n\t\t\t\"ecosystem\":         ecosystem,\n\t\t\t\"type\":              int64(GasScenesType_TransferSelf),\n\t\t\t\"created_at\":        sc.Timestamp,\n\t\t})\n\t\t_, _, err = sc.insert(values.Keys(), values.Values(), `1_history`)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tsc.TxInputsMap = txInputsMap\n\t\tsc.TxOutputsMap = txOutputsMap\n\t\treturn true, nil\n\t} else if strings.EqualFold(\"Account\", source) && strings.EqualFold(\"UTXO\", target) {\n\n\t\tvar totalAmount decimal.Decimal\n\t\tvar txOutputs []sqldb.SpentInfo\n\t\tif totalAmount, err = sc.accountBalanceSingle(ecosystem, fromID); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif totalAmount.GreaterThanOrEqual(payValue) && payValue.GreaterThan(decimal.Zero) {\n\t\t\tflag = true // The transfer was successful\n\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: 0, OutputKeyId: fromID, OutputValue: value, BlockId: blockId, Ecosystem: ecosystem, Type: consts.UTXO_Type_Self_Account})\n\t\t\ttotalAmount = totalAmount.Sub(payValue)\n\t\t\tif _, _, err = sc.updateWhere([]string{`-amount`}, []any{payValue}, \"1_keys\", types.LoadMap(map[string]any{`id`: fromID, `ecosystem`: ecosystem})); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tif balance, err = sc.accountBalanceSingle(ecosystem, fromID); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn false, fmt.Errorf(eEcoCurrentBalance, converter.IDToAddress(fromID), ecosystem)\n\t\t}\n\t\tif len(txOutputs) > 0 {\n\t\t\tsqldb.PutAllOutputsMap(txOutputs, txOutputsMap)\n\t\t}\n\t\tvalues = types.LoadMap(map[string]any{\n\t\t\t\"sender_id\":         fromID,\n\t\t\t\"sender_balance\":    balance,\n\t\t\t\"recipient_id\":      fromID,\n\t\t\t\"recipient_balance\": balance,\n\t\t\t\"amount\":            payValue,\n\t\t\t\"comment\":           source,\n\t\t\t\"status\":            int64(status),\n\t\t\t\"block_id\":          sc.BlockHeader.BlockId,\n\t\t\t\"txhash\":            sc.Hash,\n\t\t\t\"ecosystem\":         ecosystem,\n\t\t\t\"type\":              int64(GasScenesType_TransferSelf),\n\t\t\t\"created_at\":        sc.Timestamp,\n\t\t})\n\t\t_, _, err = sc.insert(values.Keys(), values.Values(), `1_history`)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tsc.TxInputsMap = txInputsMap\n\t\tsc.TxOutputsMap = txOutputsMap\n\t\treturn true, nil\n\t}\n\treturn false, errors.New(\"transfer self fail\")\n}\n\nfunc UtxoToken(sc *SmartContract, toID int64, value string) (flag bool, err error) {\n\n\tcache := sc.PrevSysPar\n\tgetParams := func(name string) (map[int64]string, error) {\n\t\tres := make(map[int64]string)\n\t\tif len(cache[name]) > 0 {\n\t\t\tifuels := make([][]string, 0)\n\t\t\terr = json.Unmarshal([]byte(cache[name]), &ifuels)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling params from json\")\n\t\t\t\treturn res, err\n\t\t\t}\n\t\t\tfor _, item := range ifuels {\n\t\t\t\tif len(item) < 2 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tres[converter.StrToInt64(item[0])] = item[1]\n\t\t\t}\n\t\t}\n\t\treturn res, nil\n\t}\n\tvar fuels = make(map[int64]string)\n\tvar wallets = make(map[int64]string)\n\tvar expediteFee decimal.Decimal\n\tfuels, err = getParams(syspar.FuelRate)\n\twallets, err = getParams(syspar.TaxesWallet)\n\n\tfromID := sc.TxSmart.KeyID\n\toutputsMap := sc.OutputsMap\n\ttxInputsMap := sc.TxInputsMap\n\ttxOutputsMap := sc.TxOutputsMap\n\tecoParams := sc.EcoParams\n\n\tvar comPercents = make(map[int64]int64)\n\tfor _, eco := range ecoParams {\n\t\tcomPercents[eco.Id] = eco.Percent\n\t}\n\tvar ecoDigits = make(map[int64]int)\n\tfor _, eco := range ecoParams {\n\t\tecoDigits[eco.Id] = eco.Digits\n\t}\n\n\t//txHash := sc.Hash\n\tecosystem := sc.TxSmart.EcosystemID\n\n\tecoDigits1 := consts.MoneyDigits\n\n\tecoDigits2 := ecoDigits[ecosystem]\n\n\tblockId := sc.BlockHeader.BlockId\n\t//dbTx := sc.DbTransaction\n\tkeyUTXO := sqldb.KeyUTXO{Ecosystem: ecosystem, KeyId: fromID}\n\n\ttxInputs := sqldb.GetUnusedOutputsMap(keyUTXO, outputsMap)\n\tif len(txInputs) == 0 {\n\t\treturn false, fmt.Errorf(eEcoCurrentBalance, converter.IDToAddress(fromID), ecosystem)\n\t}\n\n\tif expediteFee, err = expediteFeeBy(sc.TxSmart.Expedite, consts.MoneyDigits); err != nil {\n\t\treturn false, err\n\t}\n\ttotalAmount := decimal.Zero\n\n\tvar txOutputs []sqldb.SpentInfo\n\n\tfor _, input := range txInputs {\n\t\toutputValue, _ := decimal.NewFromString(input.OutputValue)\n\t\ttotalAmount = totalAmount.Add(outputValue)\n\t}\n\n\tvar outputIndex int32 = 0\n\n\t// taxes_size = 3\n\tTaxesSize := syspar.SysInt64(syspar.TaxesSize)\n\n\t// if : ecosystem = 2 ,rule : taxes ecosystem 1 and 2\n\tif ecosystem != consts.DefaultTokenEcosystem {\n\t\t// rule : taxes ecosystem 1\n\t\t{\n\t\t\tvar txOutputs1 []sqldb.SpentInfo\n\t\t\tecosystem1 := int64(consts.DefaultTokenEcosystem)\n\t\t\tkeyUTXO1 := sqldb.KeyUTXO{Ecosystem: ecosystem1, KeyId: fromID}\n\t\t\ttxInputs1 := sqldb.GetUnusedOutputsMap(keyUTXO1, outputsMap)\n\t\t\tif len(txInputs1) == 0 {\n\t\t\t\treturn false, fmt.Errorf(eEcoCurrentBalance, converter.IDToAddress(fromID), ecosystem1)\n\t\t\t}\n\t\t\ttotalAmount1 := decimal.Zero\n\n\t\t\tfor _, input1 := range txInputs1 {\n\t\t\t\toutputValue1, _ := decimal.NewFromString(input1.OutputValue)\n\t\t\t\ttotalAmount1 = totalAmount1.Add(outputValue1)\n\t\t\t}\n\t\t\tvar money1 = decimal.Zero\n\t\t\tvar fuelRate1 = decimal.Zero\n\t\t\tvar taxes1 = decimal.Zero\n\t\t\tif ret, ok := fuels[ecosystem1]; ok {\n\n\t\t\t\tfuelRate1, err = decimal.NewFromString(ret)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false, err\n\t\t\t\t}\n\t\t\t\t//\tecosystem fuelRate /10 *( bit + len(input))\n\t\t\t\tmoney1 = fuelRate1.Div(decimal.NewFromInt(10)).Mul(decimal.NewFromInt(sc.TxSize).Add(decimal.NewFromInt(int64(len(txInputs1)))))\n\t\t\t\t// utxo ecosystem 1 expediteFee\n\t\t\t\tmoney1 = money1.Add(expediteFee)\n\t\t\t\tif money1.GreaterThan(totalAmount1) {\n\t\t\t\t\tmoney1 = totalAmount1\n\t\t\t\t}\n\n\t\t\t\ttaxes1 = money1.Mul(decimal.NewFromInt(TaxesSize)).Div(decimal.New(100, 0)).Floor()\n\n\t\t\t}\n\t\t\tif money1.GreaterThan(decimal.Zero) && taxes1.GreaterThan(decimal.Zero) {\n\t\t\t\tif taxesWallet, ok := wallets[ecosystem1]; ok {\n\t\t\t\t\ttaxesID := converter.StrToInt64(taxesWallet)\n\n\t\t\t\t\tflag = true\n\t\t\t\t\t// 97%\n\t\t\t\t\ttxOutputs1 = append(txOutputs1, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: sc.BlockHeader.KeyId, OutputValue: money1.Sub(taxes1).String(), BlockId: blockId, Ecosystem: ecosystem1, Type: consts.UTXO_Type_Packaging})\n\t\t\t\t\toutputIndex++\n\t\t\t\t\t// 3%\n\t\t\t\t\ttxOutputs1 = append(txOutputs1, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: taxesID, OutputValue: taxes1.String(), BlockId: blockId, Ecosystem: ecosystem1, Type: consts.UTXO_Type_Taxes})\n\t\t\t\t\toutputIndex++\n\t\t\t\t\ttotalAmount1 = totalAmount1.Sub(money1)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif totalAmount1.GreaterThan(decimal.Zero) {\n\t\t\t\ttxOutputs1 = append(txOutputs1, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: fromID, OutputValue: totalAmount1.String(), BlockId: blockId, Ecosystem: ecosystem1, Type: consts.UTXO_Type_Output}) // The change\n\t\t\t\toutputIndex++\n\t\t\t}\n\n\t\t\tif len(txInputs1) > 0 && len(txOutputs1) > 0 {\n\t\t\t\tsqldb.PutAllOutputsMap(txInputs1, txInputsMap)\n\t\t\t\tsqldb.PutAllOutputsMap(txOutputs1, txOutputsMap)\n\t\t\t}\n\n\t\t}\n\t\t// rule : taxes ecosystem 2\n\t\t{\n\t\t\tecosystem2 := ecosystem\n\t\t\tvar money2 = decimal.Zero\n\t\t\tvar fuelRate2 = decimal.Zero\n\t\t\tvar taxes2 = decimal.Zero\n\t\t\tret, ok := fuels[ecosystem2]\n\t\t\tpercent, hasPercent := comPercents[ecosystem2]\n\t\t\tif ok && hasPercent {\n\n\t\t\t\tfuelRate2, err = decimal.NewFromString(ret)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false, err\n\t\t\t\t}\n\t\t\t\t//\tecosystem fuelRate /10 *( bit + len(input))\n\t\t\t\tmoney2 = fuelRate2.Mul(decimal.New(1, int32(ecoDigits2-ecoDigits1))).Div(decimal.NewFromInt(10)).Mul(decimal.NewFromInt(sc.TxSize).Add(decimal.NewFromInt(int64(len(txInputs)))))\n\n\t\t\t\tif money2.GreaterThan(totalAmount) {\n\t\t\t\t\tmoney2 = totalAmount\n\t\t\t\t}\n\t\t\t\tpercentMoney2 := decimal.Zero\n\t\t\t\tif percent > 0 && money2.GreaterThan(decimal.Zero) {\n\t\t\t\t\tpercentMoney2 = money2.Mul(decimal.NewFromInt(percent)).Div(decimal.New(100, 0)).Floor()\n\t\t\t\t\tif percentMoney2.GreaterThan(decimal.Zero) {\n\t\t\t\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: 0, OutputValue: percentMoney2.String(), BlockId: blockId, Ecosystem: ecosystem2, Type: consts.UTXO_Type_Combustion})\n\t\t\t\t\t\toutputIndex++\n\t\t\t\t\t\tmoney2 = money2.Sub(percentMoney2)\n\t\t\t\t\t\ttotalAmount = totalAmount.Sub(percentMoney2)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttaxes2 = money2.Mul(decimal.NewFromInt(TaxesSize)).Div(decimal.New(100, 0)).Floor()\n\t\t\t}\n\t\t\tif money2.GreaterThan(decimal.Zero) && taxes2.GreaterThan(decimal.Zero) {\n\t\t\t\tif taxesWallet, ok := wallets[ecosystem2]; ok {\n\t\t\t\t\ttaxesID := converter.StrToInt64(taxesWallet)\n\n\t\t\t\t\tflag = true\n\t\t\t\t\t// 97%\n\t\t\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: sc.BlockHeader.KeyId, OutputValue: money2.Sub(taxes2).String(), BlockId: blockId, Ecosystem: ecosystem2, Type: consts.UTXO_Type_Packaging})\n\t\t\t\t\toutputIndex++\n\t\t\t\t\t// 3%\n\t\t\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: taxesID, OutputValue: taxes2.String(), BlockId: blockId, Ecosystem: ecosystem2, Type: consts.UTXO_Type_Taxes})\n\t\t\t\t\toutputIndex++\n\t\t\t\t\ttotalAmount = totalAmount.Sub(money2)\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\t// if : ecosystem = 1 , rule : taxes ecosystem 1\n\tif ecosystem == consts.DefaultTokenEcosystem {\n\t\tecosystem1 := int64(consts.DefaultTokenEcosystem)\n\t\tvar money1 = decimal.Zero\n\t\tvar fuelRate1 = decimal.Zero\n\t\tvar taxes1 = decimal.Zero\n\t\tif ret, ok := fuels[ecosystem1]; ok {\n\n\t\t\tfuelRate1, err = decimal.NewFromString(ret)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t} else {\n\t\t\t\t//\tecosystem fuelRate /10 *( bit + len(input))\n\t\t\t\tmoney1 = fuelRate1.Div(decimal.NewFromInt(10)).Mul(decimal.NewFromInt(sc.TxSize).Add(decimal.NewFromInt(int64(len(txInputs)))))\n\t\t\t\t// utxo ecosystem 1 expediteFee\n\t\t\t\tmoney1 = money1.Add(expediteFee)\n\t\t\t\tif money1.GreaterThan(totalAmount) {\n\t\t\t\t\tmoney1 = totalAmount\n\t\t\t\t}\n\t\t\t\ttaxes1 = money1.Mul(decimal.NewFromInt(TaxesSize)).Div(decimal.New(100, 0)).Floor()\n\t\t\t}\n\t\t}\n\t\tif money1.GreaterThan(decimal.Zero) && taxes1.GreaterThan(decimal.Zero) {\n\t\t\tif taxesWallet, ok := wallets[ecosystem1]; ok {\n\t\t\t\ttaxesID := converter.StrToInt64(taxesWallet)\n\n\t\t\t\tflag = true\n\t\t\t\t// 97%\n\t\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: sc.BlockHeader.KeyId, OutputValue: money1.Sub(taxes1).String(), BlockId: blockId, Ecosystem: ecosystem1, Type: consts.UTXO_Type_Packaging})\n\t\t\t\toutputIndex++\n\t\t\t\t// 3%\n\t\t\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: taxesID, OutputValue: taxes1.String(), BlockId: blockId, Ecosystem: ecosystem1, Type: consts.UTXO_Type_Taxes})\n\t\t\t\toutputIndex++\n\t\t\t\ttotalAmount = totalAmount.Sub(money1)\n\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpayValue, _ := decimal.NewFromString(value)\n\tif totalAmount.GreaterThanOrEqual(payValue) && payValue.GreaterThan(decimal.Zero) {\n\t\tflag = true // The transfer was successful\n\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: toID, OutputValue: value, BlockId: blockId, Ecosystem: ecosystem, Type: consts.UTXO_Type_Transfer})\n\t\toutputIndex++\n\t\ttotalAmount = totalAmount.Sub(payValue)\n\t} else {\n\t\tflag = false\n\t\terr = fmt.Errorf(eEcoCurrentBalance, converter.IDToAddress(fromID), ecosystem)\n\t}\n\n\t// The change\n\tif totalAmount.GreaterThan(decimal.Zero) {\n\t\ttxOutputs = append(txOutputs, sqldb.SpentInfo{OutputIndex: outputIndex, OutputKeyId: fromID, OutputValue: totalAmount.String(), BlockId: blockId, Ecosystem: ecosystem, Type: consts.UTXO_Type_Output}) // The change\n\t\toutputIndex++\n\t}\n\tif len(txInputs) > 0 && len(txOutputs) > 0 {\n\t\tsqldb.PutAllOutputsMap(txInputs, txInputsMap)\n\t\tsqldb.PutAllOutputsMap(txOutputs, txOutputsMap)\n\t}\n\tsc.TxInputsMap = txInputsMap\n\tsc.TxOutputsMap = txOutputsMap\n\treturn flag, err\n}\n"
  },
  {
    "path": "packages/smart/smart_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype TestSmart struct {\n\tInput  string\n\tOutput string\n}\n\nfunc TestNewContract(t *testing.T) {\n\ttest := []TestSmart{\n\t\t{`contract NewCitizen {\n\t\t\tdata {\n\t\t\t\tPublic bytes\n\t\t\t\tMyVal  string\n\t\t\t}\n\t\t\t func conditions {\n\t\t\t\tPrintln( \"Front\")\n\t\t\t\t//$tmp = \"Test string\"\n//\t\t\t\tPrintln(\"NewCitizen Front\", $tmp, $key_id, $ecosystem_id, $PublicKey )\n\t\t\t}\n\t\t\tsettings {\n\t\t\t\tabc = 123\n\t\t\t}\n\t\t\tfunc action {\n//\t\t\t\tPrintln(\"NewCitizen Main\", $tmp, $type, $key_id )\n//\t\t\t\tDBInsert(Sprintf( \"%d_citizens\", $ecosystem_id), \"public_key,block_id\", $PublicKey, $block)\n\t\t\t}\n}\t\t\t\n\t\t`, ``},\n\t}\n\towner := script.OwnerInfo{\n\t\tStateID:  1,\n\t\tActive:   false,\n\t\tTableID:  1,\n\t\tWalletID: 0,\n\t\tTokenID:  0,\n\t}\n\tInitVM()\n\tfor _, item := range test {\n\t\tif err := script.GetVM().Compile([]rune(item.Input), &owner); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\t}\n\tcnt := GetContract(`NewCitizen`, 1)\n\tcfunc := cnt.GetFunc(`conditions`)\n\t_, err := script.VMRun(script.GetVM(), cfunc, nil, map[string]any{}, nil)\n\tif err != nil {\n\t\tt.Error(err)\n\t}\n}\n\nfunc TestCheckAppend(t *testing.T) {\n\tappendTestContract := `contract AppendTest {\n\t\taction {\n\t\t\tvar list array\n\t\t\tlist = Append(list, \"naw_value\")\n\t\t\tPrintln(list)\n\t\t}\n\t}`\n\n\towner := script.OwnerInfo{\n\t\tStateID:  1,\n\t\tActive:   false,\n\t\tTableID:  1,\n\t\tWalletID: 0,\n\t\tTokenID:  0,\n\t}\n\n\trequire.NoError(t, script.GetVM().Compile([]rune(appendTestContract), &owner))\n\n\tcnt := GetContract(\"AppendTest\", 1)\n\tcfunc := cnt.GetFunc(\"action\")\n\n\t_, err := script.VMRun(script.GetVM(), cfunc, nil, map[string]any{}, nil)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "packages/smart/sysrollback.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tSysName = `@system`\n)\n\ntype SysRollData struct {\n\tType        string `json:\"type,omitempty\"`\n\tEcosystemID int64  `json:\"ecosystem,omitempty\"`\n\tID          int64  `json:\"id,omitempty\"`\n\tData        string `json:\"data,omitempty\"`\n\tTableName   string `json:\"table,omitempty\"`\n}\n\nfunc SysRollback(sc *SmartContract, data SysRollData) error {\n\tout, err := marshalJSON(data, `marshaling sys rollback`)\n\tif err != nil {\n\t\treturn err\n\t}\n\trollbackSys := &types.RollbackTx{\n\t\tBlockId:   sc.BlockHeader.BlockId,\n\t\tTxHash:    sc.Hash,\n\t\tNameTable: SysName,\n\t\tTableId:   converter.Int64ToStr(sc.TxSmart.EcosystemID),\n\t\tData:      string(out),\n\t\tDataHash:  crypto.Hash(out),\n\t}\n\tsc.RollBackTx = append(sc.RollBackTx, rollbackSys)\n\treturn nil\n}\n\n// SysRollbackTable is rolling back table\nfunc SysRollbackTable(dbTx *sqldb.DbTransaction, sysData SysRollData) error {\n\terr := dbTx.DropTable(sysData.TableName)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"dropping table\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// SysRollbackView is rolling back table\nfunc SysRollbackView(DbTransaction *sqldb.DbTransaction, sysData SysRollData) error {\n\terr := sqldb.DropView(DbTransaction, sysData.TableName)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"dropping view\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// SysRollbackColumn is rolling back column\nfunc SysRollbackColumn(dbTx *sqldb.DbTransaction, sysData SysRollData) error {\n\treturn dbTx.AlterTableDropColumn(sysData.TableName, sysData.Data)\n}\n\n// SysRollbackContract performs rollback for the contract\nfunc SysRollbackContract(name string, EcosystemID int64) error {\n\tvm := script.GetVM()\n\tif c := VMGetContract(vm, name, uint32(EcosystemID)); c != nil {\n\t\tid := c.Info().ID\n\t\tif int(id) != len(vm.Children)-1 {\n\t\t\terr := fmt.Errorf(eRollbackContract, id, len(vm.Children)-1)\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError, \"error\": err}).Error(\"rollback contract\")\n\t\t\treturn err\n\t\t}\n\t\tvm.Children = vm.Children[:id]\n\t\tdelete(vm.Objects, c.Name)\n\t}\n\n\treturn nil\n}\n\nfunc SysRollbackNewContract(sysData SysRollData, EcosystemID string) error {\n\tcontractList, err := script.ContractsList(sysData.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, contract := range contractList {\n\t\tif err := SysRollbackContract(contract, converter.StrToInt64(EcosystemID)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// SysFlushContract is flushing contract\nfunc SysFlushContract(iroot any, id int64, active bool) error {\n\troot := iroot.(*script.CodeBlock)\n\tif id != 0 {\n\t\tif len(root.Children) != 1 || root.Children[0].Type != script.ObjectType_Contract {\n\t\t\treturn fmt.Errorf(`only one contract must be in the record`)\n\t\t}\n\t}\n\tfor i, item := range root.Children {\n\t\tif item.Type == script.ObjectType_Contract {\n\t\t\troot.Children[i].GetContractInfo().Owner.TableID = id\n\t\t\troot.Children[i].GetContractInfo().Owner.Active = active\n\t\t}\n\t}\n\tscript.GetVM().FlushBlock(root)\n\treturn nil\n}\n\n// SysSetContractWallet changes WalletID of the contract in smartVM\nfunc SysSetContractWallet(tblid, state int64, wallet int64) error {\n\tfor i, item := range script.GetVM().CodeBlock.Children {\n\t\tif item != nil && item.Type == script.ObjectType_Contract {\n\t\t\tcinfo := item.GetContractInfo()\n\t\t\tif cinfo.Owner.TableID == tblid && cinfo.Owner.StateID == uint32(state) {\n\t\t\t\tscript.GetVM().Children[i].GetContractInfo().Owner.WalletID = wallet\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// SysRollbackEditContract rollbacks the contract\nfunc SysRollbackEditContract(transaction *sqldb.DbTransaction, sysData SysRollData,\n\tEcosystemID string) error {\n\n\tfields, err := transaction.GetOneRowTransaction(`select * from \"1_contracts\" where id=?`,\n\t\tsysData.ID).String()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(fields[\"value\"]) > 0 {\n\t\tvar owner *script.OwnerInfo\n\t\tfor i, item := range script.GetVM().CodeBlock.Children {\n\t\t\tif item != nil && item.Type == script.ObjectType_Contract {\n\t\t\t\tcinfo := item.GetContractInfo()\n\t\t\t\tif cinfo.Owner.TableID == sysData.ID &&\n\t\t\t\t\tcinfo.Owner.StateID == uint32(converter.StrToInt64(EcosystemID)) {\n\t\t\t\t\towner = script.GetVM().Children[i].GetContractInfo().Owner\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif owner == nil {\n\t\t\terr = errContractNotFound\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError, \"error\": err}).Error(\"getting existing contract\")\n\t\t\treturn err\n\t\t}\n\t\twallet := owner.WalletID\n\t\tif len(fields[\"wallet_id\"]) > 0 {\n\t\t\twallet = converter.StrToInt64(fields[\"wallet_id\"])\n\t\t}\n\t\troot, err := script.GetVM().CompileBlock([]rune(fields[\"value\"]),\n\t\t\t&script.OwnerInfo{StateID: uint32(owner.StateID), WalletID: wallet, TokenID: owner.TokenID})\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError, \"error\": err}).Error(\"compiling contract\")\n\t\t\treturn err\n\t\t}\n\t\terr = SysFlushContract(root, owner.TableID, owner.Active)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.VMError, \"error\": err}).Error(\"flushing contract\")\n\t\t\treturn err\n\t\t}\n\t} else if len(fields[\"wallet_id\"]) > 0 {\n\t\treturn SysSetContractWallet(sysData.ID, converter.StrToInt64(EcosystemID),\n\t\t\tconverter.StrToInt64(fields[\"wallet_id\"]))\n\t}\n\treturn nil\n}\n\n// SysRollbackEcosystem is rolling back ecosystem\nfunc SysRollbackEcosystem(dbTx *sqldb.DbTransaction, sysData SysRollData) error {\n\ttables := make([]string, 0)\n\tfor table := range converter.FirstEcosystemTables {\n\t\ttables = append(tables, table)\n\t\terr := dbTx.Delete(`1_`+table, fmt.Sprintf(`where ecosystem='%d'`, sysData.ID))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif sysData.ID == 1 {\n\t\ttables = append(tables, `node_ban_logs`, `bad_blocks`, `platform_parameters`, `ecosystems`)\n\t\tfor _, name := range tables {\n\t\t\terr := dbTx.DropTable(fmt.Sprintf(\"%d_%s\", sysData.ID, name))\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"dropping table\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t} else {\n\t\tvm := script.GetVM()\n\t\tfor vm.Children[len(vm.Children)-1].Type == script.ObjectType_Contract {\n\t\t\tcinfo := vm.Children[len(vm.Children)-1].GetContractInfo()\n\t\t\tif int64(cinfo.Owner.StateID) != sysData.ID {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif err := SysRollbackContract(cinfo.Name, sysData.ID); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// SysRollbackActivate sets Deactive status of the contract in smartVM\nfunc SysRollbackActivate(sysData SysRollData) error {\n\tActivateContract(sysData.ID, sysData.EcosystemID, false)\n\treturn nil\n}\n\n// SysRollbackDeactivate sets Active status of the contract in smartVM\nfunc SysRollbackDeactivate(sysData SysRollData) error {\n\tActivateContract(sysData.ID, sysData.EcosystemID, true)\n\treturn nil\n}\n\n// SysRollbackDeleteColumn is rolling back delete column\nfunc SysRollbackDeleteColumn(dbTx *sqldb.DbTransaction, sysData SysRollData) error {\n\tvar (\n\t\tdata map[string]string\n\t)\n\terr := unmarshalJSON([]byte(sysData.Data), &data, `rollback delete to json`)\n\tif err != nil {\n\t\treturn err\n\t}\n\tsqlColType, err := columnType(data[\"type\"])\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = dbTx.AlterTableAddColumn(sysData.TableName, data[\"name\"], sqlColType)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"adding column to the table\")\n\t}\n\treturn nil\n}\n\n// SysRollbackDeleteTable is rolling back delete table\nfunc SysRollbackDeleteTable(dbTx *sqldb.DbTransaction, sysData SysRollData) error {\n\tvar (\n\t\tdata    TableInfo\n\t\tcolsSQL string\n\t)\n\terr := unmarshalJSON([]byte(sysData.Data), &data, `rollback delete table to json`)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor key, item := range data.Columns {\n\t\tcolsSQL += `\"` + key + `\" ` + typeToPSQL[item] + \" ,\\n\"\n\t}\n\terr = sqldb.CreateTable(dbTx, sysData.TableName, strings.TrimRight(colsSQL, \",\\n\"))\n\tif err != nil {\n\t\treturn logErrorDB(err, \"creating tables\")\n\t}\n\n\tprefix, _ := PrefixName(sysData.TableName)\n\tdata.Table.SetTablePrefix(prefix)\n\terr = data.Table.Create(dbTx)\n\tif err != nil {\n\t\treturn logErrorDB(err, \"insert table info\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/smart/utils.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage smart\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\t\"github.com/shopspring/decimal\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc logError(err error, errType string, comment string) error {\n\tlog.WithFields(log.Fields{\"type\": errType, \"error\": err}).Error(comment)\n\treturn err\n}\n\nfunc logErrorf(pattern string, param any, errType string, comment string) error {\n\terr := fmt.Errorf(pattern, param)\n\tlog.WithFields(log.Fields{\"type\": errType, \"error\": err}).Error(comment)\n\treturn err\n}\n\nfunc logErrorShort(err error, errType string) error {\n\treturn logError(err, errType, err.Error())\n}\n\nfunc logErrorfShort(pattern string, param any, errType string) error {\n\treturn logErrorShort(fmt.Errorf(pattern, param), errType)\n}\n\nfunc logErrorValue(err error, errType string, comment, value string) error {\n\tlog.WithFields(log.Fields{\"type\": errType, \"error\": err, \"value\": value}).Error(comment)\n\treturn err\n}\n\nfunc logErrorDB(err error, comment string) error {\n\treturn logError(err, consts.DBError, comment)\n}\n\nfunc unmarshalJSON(input []byte, v any, comment string) (err error) {\n\td := json.NewDecoder(bytes.NewReader(input))\n\td.UseNumber()\n\tif err = d.Decode(&v); err != nil {\n\t\treturn errors.Wrap(err, comment)\n\t}\n\treturn nil\n}\n\nfunc marshalJSON(v any, comment string) (out []byte, err error) {\n\tout, err = json.Marshal(v)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, comment)\n\t}\n\treturn\n}\n\nfunc validateAccess(sc *SmartContract, funcName string) error {\n\tcondition := syspar.GetAccessExec(utils.ToSnakeCase(funcName))\n\n\tif err := Eval(sc, condition); err != nil {\n\t\terr = fmt.Errorf(eAccessContract, funcName, condition)\n\t\treturn logError(err, consts.IncorrectCallingContract, err.Error())\n\t}\n\n\treturn nil\n}\n\nfunc FillTxData(fieldInfos []*script.FieldInfo, params map[string]any) (map[string]any, error) {\n\ttxData := make(map[string]any)\n\tfor _, fitem := range fieldInfos {\n\t\tvar (\n\t\t\tv     any\n\t\t\tok    bool\n\t\t\terr   error\n\t\t\tindex = fitem.Name\n\t\t)\n\n\t\tif _, ok := params[index]; !ok {\n\t\t\tif fitem.ContainsTag(script.TagOptional) {\n\t\t\t\ttxData[index] = script.GetFieldDefaultValue(fitem.Original)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(eParamNotFound, index)\n\t\t}\n\n\t\tswitch fitem.Original {\n\t\tcase script.DtBool:\n\t\t\tif v, ok = params[index].(bool); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid bool type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\tcase script.DtFloat:\n\t\t\tswitch val := params[index].(type) {\n\t\t\tcase float64:\n\t\t\t\tv = val\n\t\t\tcase uint64:\n\t\t\t\tv = float64(val)\n\t\t\tcase int64:\n\t\t\t\tv = float64(val)\n\t\t\tdefault:\n\t\t\t\terr = fmt.Errorf(\"invalid float type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\tcase script.DtInt:\n\t\t\tswitch t := params[index].(type) {\n\t\t\tcase int:\n\t\t\t\tv = int64(t)\n\t\t\tcase int8:\n\t\t\t\tv = int64(t)\n\t\t\tcase int16:\n\t\t\t\tv = int64(t)\n\t\t\tcase int32:\n\t\t\t\tv = int64(t)\n\t\t\tcase int64:\n\t\t\t\tv = t\n\t\t\tcase uint:\n\t\t\t\tv = int64(t)\n\t\t\tcase uint8:\n\t\t\t\tv = int64(t)\n\t\t\tcase uint16:\n\t\t\t\tv = int64(t)\n\t\t\tcase uint32:\n\t\t\t\tv = int64(t)\n\t\t\tcase uint64:\n\t\t\t\tv = int64(t)\n\t\t\tdefault:\n\t\t\t\terr = fmt.Errorf(\"invalid int type\")\n\t\t\t}\n\t\tcase script.DtAddress:\n\t\t\tswitch t := params[index].(type) {\n\t\t\tcase int64:\n\t\t\t\tv = t\n\t\t\tcase uint64:\n\t\t\t\tv = int64(t)\n\t\t\tdefault:\n\t\t\t\terr = fmt.Errorf(\"invalid int type\")\n\t\t\t}\n\t\tcase script.DtMoney:\n\t\t\tvar s string\n\t\t\tif s, ok = params[index].(string); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid money type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tv, err = decimal.NewFromString(s)\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif v.(decimal.Decimal).LessThan(decimal.New(1, 0)) ||\n\t\t\t\tv.(decimal.Decimal).\n\t\t\t\t\tMod(decimal.New(1, 0)).\n\t\t\t\t\tGreaterThan(decimal.Zero) {\n\t\t\t\terr = fmt.Errorf(\"inconsistent with the smallest reference unit and its integer multiples\")\n\t\t\t\tbreak\n\t\t\t}\n\t\tcase script.DtString:\n\t\t\tif v, ok = params[index].(string); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid string type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\tcase script.DtBytes:\n\t\t\tif v, ok = params[index].([]byte); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid bytes type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\tcase script.DtArray:\n\t\t\tif v, ok = params[index].([]any); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid array type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tfor i, subv := range v.([]any) {\n\t\t\t\tswitch val := subv.(type) {\n\t\t\t\tcase map[any]any:\n\t\t\t\t\timap := make(map[string]any)\n\t\t\t\t\tfor ikey, ival := range val {\n\t\t\t\t\t\timap[fmt.Sprint(ikey)] = ival\n\t\t\t\t\t}\n\t\t\t\t\tv.([]any)[i] = types.LoadMap(imap)\n\t\t\t\t}\n\t\t\t}\n\t\tcase script.DtMap:\n\t\t\tvar val map[any]any\n\t\t\tif val, ok = params[index].(map[any]any); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid map type\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t\timap := make(map[string]any)\n\t\t\tfor ikey, ival := range val {\n\t\t\t\timap[fmt.Sprint(ikey)] = ival\n\t\t\t}\n\t\t\tv = types.LoadMap(imap)\n\t\tcase script.DtFile:\n\t\t\tvar val map[string]any\n\t\t\tif val, ok = params[index].(map[string]any); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid file type\")\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif v, ok = types.NewFileFromMap(val); !ok {\n\t\t\t\terr = fmt.Errorf(\"invalid attrs of file\")\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid param '%s': %w\", index, err)\n\t\t}\n\n\t\tif _, ok = txData[fitem.Name]; !ok {\n\t\t\ttxData[fitem.Name] = v\n\t\t}\n\t}\n\n\tif len(txData) != len(fieldInfos) {\n\t\treturn nil, fmt.Errorf(\"invalid number of parameters\")\n\t}\n\n\treturn txData, nil\n}\n"
  },
  {
    "path": "packages/statsd/statsd.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage statsd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\n\t\"github.com/cactus/go-statsd-client/v5/statsd\"\n)\n\nconst (\n\tCount = \".count\"\n\tTime  = \".time\"\n)\n\nvar Client statsd.Statter\n\nfunc Init(conf conf.StatsDConfig) error {\n\tvar err error\n\tconfig := &statsd.ClientConfig{\n\t\tAddress:     fmt.Sprintf(\"%s:%d\", conf.Host, conf.Port),\n\t\tPrefix:      conf.Name,\n\t\tUseBuffered: false,\n\t}\n\tClient, err = statsd.NewClientWithConfig(config)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc Close() {\n\tif Client != nil {\n\t\tClient.Close()\n\t}\n}\n\nfunc APIRouteCounterName(method, pattern string) string {\n\trouteCounterName := strings.Replace(strings.Replace(pattern, \":\", \"\", -1), \"/\", \".\", -1)\n\treturn \"api.\" + strings.ToLower(method) + \".\" + routeCounterName\n}\n\nfunc DaemonCounterName(daemonName string) string {\n\treturn \"daemon.\" + daemonName\n}\n"
  },
  {
    "path": "packages/storage/kvdb/leveldb/leveldb.go",
    "content": "package leveldb\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/syndtr/goleveldb/leveldb\"\n\t\"github.com/syndtr/goleveldb/leveldb/iterator\"\n\t\"github.com/syndtr/goleveldb/leveldb/opt\"\n\t\"github.com/syndtr/goleveldb/leveldb/util\"\n)\n\nvar DBlevel *leveldb.DB\nvar GLeveldbIsactive bool\n\ntype levelDBGetterPutterDeleter interface {\n\tGet([]byte, *opt.ReadOptions) ([]byte, error)\n\tPut([]byte, []byte, *opt.WriteOptions) error\n\tWrite(batch *leveldb.Batch, wo *opt.WriteOptions) error\n\tDelete([]byte, *opt.WriteOptions) error\n\tNewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator\n}\n\nfunc GetLevelDB(tx *leveldb.Transaction) levelDBGetterPutterDeleter {\n\tif tx != nil {\n\t\treturn tx\n\t}\n\treturn DBlevel\n}\n\nfunc prefixFunc(prefix string) func([]byte) []byte {\n\treturn func(hash []byte) []byte {\n\t\treturn []byte(prefix + string(hash))\n\t}\n}\n\nfunc prefixStringFunc(prefix string) func(key string) []byte {\n\treturn func(key string) []byte {\n\t\treturn []byte(prefix + key)\n\t}\n}\n\nfunc Init_leveldb(filename string) error {\n\tvar err error\n\tDBlevel, err = leveldb.OpenFile(filename, nil)\n\tif err == nil {\n\t\tGLeveldbIsactive = true\n\t}\n\n\treturn err\n}\n\nfunc Struct2Map(obj any) map[string]any {\n\tt := reflect.TypeOf(obj)\n\tv := reflect.ValueOf(obj)\n\n\tvar data = make(map[string]any)\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tdata[t.Field(i).Name] = v.Field(i).Interface()\n\t}\n\treturn data\n}\nfunc DBGetAllKey(prefix string, bvalue bool) (*[]string, error) {\n\tvar (\n\t\tret []string\n\t\t//key []string\n\t)\n\tfound := prefix != \"nil\"\n\titer := DBlevel.NewIterator(nil, nil)\n\tfor iter.Next() {\n\t\tkey := string(iter.Key())\n\t\tif found {\n\t\t\tif strings.HasPrefix(key, prefix) {\n\t\t\t\tif bvalue {\n\t\t\t\t\tvalue := string(iter.Value())\n\t\t\t\t\ts := fmt.Sprintf(\"Key[%s]=[%s]\\n\", key, value)\n\t\t\t\t\tret = append(ret, s)\n\t\t\t\t} else {\n\t\t\t\t\tret = append(ret, key)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif bvalue {\n\t\t\t\tvalue := string(iter.Value())\n\t\t\t\ts := fmt.Sprintf(\"Key[%s]=[%s]\\n\", key, value)\n\t\t\t\tret = append(ret, s)\n\t\t\t} else {\n\t\t\t\tret = append(ret, key)\n\t\t\t}\n\t\t}\n\n\t}\n\titer.Release()\n\treturn &ret, iter.Error()\n}\n"
  },
  {
    "path": "packages/storage/kvdb/redis/goredis.go",
    "content": "package redis\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\n\t\"github.com/go-redis/redis\"\n)\n\nvar (\n\tGclient0       *redis.Client //\n\tGclient1       *redis.Client //\n\tGRedisIsactive bool\n\trediserr       = errors.New(\"redis no run error\")\n)\n\ntype RedisParams struct {\n\tKey   string `json:\"key\"`\n\tValue string `json:\"value\"`\n}\n\nfunc RedisInit(conf conf.RedisConfig) error {\n\tvar (\n\t\terr error\n\t)\n\tGRedisIsactive = false\n\n\tGclient0 = redis.NewClient(&redis.Options{\n\t\tAddr:     fmt.Sprintf(\"%s:%d\", conf.Host, conf.Port),\n\t\tPassword: conf.Password, // no password set\n\t\tDB:       conf.DbName,   // use default DB\n\t})\n\t_, err = Gclient0.Ping().Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tGclient1 = redis.NewClient(&redis.Options{\n\t\tAddr:     fmt.Sprintf(\"%s:%d\", conf.Host, conf.Port),\n\t\tPassword: conf.Password, // no password set\n\t\tDB:       1,             // use default DB\n\t})\n\t_, err = Gclient1.Ping().Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tGRedisIsactive = true\n\n\treturn nil\n}\n\nfunc (rp *RedisParams) Setdb() error {\n\terr := rediserr\n\tif GRedisIsactive {\n\t\terr = Gclient0.Set(rp.Key, rp.Value, 0).Err()\n\t}\n\n\treturn err\n}\n\nfunc (rp *RedisParams) Getdb() error {\n\terr := rediserr\n\tif GRedisIsactive {\n\t\tval, err1 := Gclient0.Get(rp.Key).Result()\n\t\trp.Value = val\n\t\treturn err1\n\t}\n\treturn err\n}\n\nfunc (rp *RedisParams) Getdbsize() (int64, error) {\n\terr := rediserr\n\tif GRedisIsactive {\n\t\treturn Gclient0.DBSize().Result()\n\t}\n\treturn 0, err\n}\n\nfunc (rp *RedisParams) Cleardb() error {\n\terr := rediserr\n\tvar cursor uint64\n\tvar n int\n\tvar keys []string\n\n\tif GRedisIsactive {\n\t\terr = nil\n\t\tfor {\n\t\t\tvar key []string\n\t\t\tvar err error\n\t\t\tkey, cursor, err = Gclient0.Scan(cursor, \"*\", 10).Result()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tn += len(keys)\n\t\t\tkeys = append(keys, key...)\n\t\t\tif cursor == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tfor _, k := range keys {\n\t\t\terr = Gclient0.Del(k).Err()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t}\n\treturn err\n}\n\nfunc (rp *RedisParams) Getdb1() error {\n\terr := rediserr\n\tif GRedisIsactive {\n\t\tval, err1 := Gclient1.Get(rp.Key).Result()\n\t\trp.Value = val\n\t\treturn err1\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "packages/storage/kvdb/redis/maxblockid.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage redis\n\nimport (\n\t\"github.com/vmihailenco/msgpack/v5\"\n)\n\n// BlockID is model\ntype BlockID struct {\n\tID   int64\n\tTime int64\n\tName string\n}\n\nvar MihPrefix = \"blockid-\"\n\n//marshal\nfunc (b *BlockID) Marshal() ([]byte, error) {\n\tif res, err := msgpack.Marshal(b); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn res, err\n\t}\n}\n\n//unmarshal\nfunc (b *BlockID) Unmarshal(bt []byte) error {\n\tif err := msgpack.Unmarshal(bt, &b); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n//Get by name\nfunc (b *BlockID) GetbyName(name string) (bool, error) {\n\trp := &RedisParams{\n\t\tKey: MihPrefix + name,\n\t}\n\tif err := rp.Getdb1(); err != nil {\n\t\treturn false, err\n\t}\n\tif err := b.Unmarshal([]byte(rp.Value)); err != nil {\n\t\treturn false, err\n\t}\n\treturn true, nil\n}\n\n//Get by name\nfunc (b *BlockID) GetRangeByName(n1, n2 string, count int64) (bool, error) {\n\tvar nb1, nb2 BlockID\n\trp1 := &RedisParams{\n\t\tKey: MihPrefix + n1,\n\t}\n\tif err := rp1.Getdb1(); err != nil {\n\t\tif err.Error() == \"redis: nil\" {\n\t\t\trp := &RedisParams{}\n\t\t\tnum, err := rp.Getdbsize()\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tif num > count {\n\t\t\t\treturn true, err\n\t\t\t} else {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\t//return false, err\n\t\t}\n\t\treturn false, err\n\t}\n\tif err := nb1.Unmarshal([]byte(rp1.Value)); err != nil {\n\t\treturn false, err\n\t}\n\n\trp2 := &RedisParams{\n\t\tKey: MihPrefix + n2,\n\t}\n\tif err := rp2.Getdb1(); err != nil {\n\t\treturn false, err\n\t}\n\tif err := nb2.Unmarshal([]byte(rp2.Value)); err != nil {\n\t\treturn false, err\n\t}\n\n\tif (nb2.ID - nb1.ID) > count {\n\t\treturn true, nil\n\t}\n\n\treturn false, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/app_param.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// AppParam is model\ntype AppParam struct {\n\tecosystem  int64\n\tID         int64  `gorm:\"primary_key;not null\"`\n\tAppID      int64  `gorm:\"not null\"`\n\tName       string `gorm:\"not null;size:100\"`\n\tValue      string `gorm:\"not null\"`\n\tConditions string `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (sp *AppParam) TableName() string {\n\tif sp.ecosystem == 0 {\n\t\tsp.ecosystem = 1\n\t}\n\treturn `1_app_params`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (sp *AppParam) SetTablePrefix(tablePrefix string) {\n\tsp.ecosystem = converter.StrToInt64(tablePrefix)\n}\n\n// Get is retrieving model from database\nfunc (sp *AppParam) Get(dbTx *DbTransaction, app int64, name string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"ecosystem=? and app_id=? and name = ?\",\n\t\tsp.ecosystem, app, name).First(sp))\n}\n\n// GetAllAppParameters is returning all state parameters\nfunc (sp *AppParam) GetAllAppParameters(app int64, offset, limit *int, names []string) ([]AppParam, error) {\n\tparameters := make([]AppParam, 0)\n\tq := DBConn.Table(sp.TableName()).Where(`ecosystem = ?`, sp.ecosystem).Where(`app_id = ?`, app)\n\tif len(names) > 0 {\n\t\t//if any select names,then all return\n\t\tq = q.Where(\"name IN ?\", names)\n\t} else {\n\t\tif offset != nil {\n\t\t\tq = q.Offset(*offset)\n\t\t}\n\t\tif limit != nil {\n\t\t\tq = q.Limit(*limit)\n\t\t}\n\t}\n\terr := q.Find(&parameters).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn parameters, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/bad_blocks.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"time\"\n)\n\ntype BadBlocks struct {\n\tID             int64\n\tProducerNodeId int64\n\tBlockId        int64\n\tConsumerNodeId int64\n\tBlockTime      time.Time\n\tDeleted        bool\n}\n\n// TableName returns name of table\nfunc (r BadBlocks) TableName() string {\n\treturn \"1_bad_blocks\"\n}\n\n// BanRequests represents count of unique ban requests for node\ntype BanRequests struct {\n\tProducerNodeId int64\n\tCount          int64\n}\n\n// GetNeedToBanNodes is returns list of ban requests for each node\nfunc (r *BadBlocks) GetNeedToBanNodes(now time.Time, blocksPerNode int) ([]BanRequests, error) {\n\tvar res []BanRequests\n\n\terr := DBConn.\n\t\tRaw(\n\t\t\t`SELECT\n\t\t\t\tproducer_node_id,\n\t\t\t\tCOUNT(consumer_node_id) as count\n\t\t\tFROM (\n\t\t\t\tSELECT\n\t\t\t\t\tproducer_node_id,\n\t\t\t\t\tconsumer_node_id,\n\t\t\t\t\tcount(DISTINCT block_id)\n\t\t\t\tFROM\n\t\t\t\t\"1_bad_blocks\"\n\t\t\t\tWHERE\n\t\t\t\t\tblock_time > ?::date - interval '24 hours'\n\t\t\t\t\tAND deleted = 0\n\t\t\t\tGROUP BY\n\t\t\t\t\tproducer_node_id,\n\t\t\t\t\tconsumer_node_id\n\t\t\t\tHAVING\n\t\t\t\t\tcount(DISTINCT block_id) >= ?) AS tbl\n\t\t\tGROUP BY\n\t\t\tproducer_node_id`,\n\t\t\tnow,\n\t\t\tblocksPerNode,\n\t\t).\n\t\tScan(&res).\n\t\tError\n\n\treturn res, err\n}\n\nfunc (r *BadBlocks) GetNodeBlocks(nodeId int64, now time.Time) ([]BadBlocks, error) {\n\tvar res []BadBlocks\n\terr := DBConn.\n\t\tTable(r.TableName()).\n\t\tModel(&BadBlocks{}).\n\t\tWhere(\n\t\t\t\"producer_node_id = ? AND block_time > ?::date - interval '24 hours' AND deleted = ?\",\n\t\t\tnodeId,\n\t\t\tnow,\n\t\t\tfalse,\n\t\t).\n\t\tScan(&res).\n\t\tError\n\n\treturn res, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/binary.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nconst BinaryTableSuffix = \"_binaries\"\n\n// Binary represents record of {prefix}_binaries table\ntype Binary struct {\n\tecosystem int64\n\tID        int64\n\tName      string\n\tData      []byte\n\tHash      string\n\tMimeType  string\n}\n\n// SetTablePrefix is setting table prefix\nfunc (b *Binary) SetTablePrefix(prefix string) {\n\tb.ecosystem = converter.StrToInt64(prefix)\n}\n\n// SetTableName sets name of table\nfunc (b *Binary) SetTableName(tableName string) {\n\tecosystem, _ := converter.ParseName(tableName)\n\tb.ecosystem = ecosystem\n}\n\n// TableName returns name of table\nfunc (b *Binary) TableName() string {\n\tif b.ecosystem == 0 {\n\t\tb.ecosystem = 1\n\t}\n\treturn `1_binaries`\n}\n\n// Get is retrieving model from database\nfunc (b *Binary) Get(appID int64, account, name string) (bool, error) {\n\treturn isFound(DBConn.Where(\"ecosystem=? and app_id = ? AND account = ? AND name = ?\",\n\t\tb.ecosystem, appID, account, name).Select(\"id,name,hash\").First(b))\n}\n\n// Link returns link to binary data\nfunc (b *Binary) Link() string {\n\treturn fmt.Sprintf(`/data/%s/%d/%s/%s`, b.TableName(), b.ID, \"data\", b.Hash)\n}\n\n// GetByID is retrieving model from db by id\nfunc (b *Binary) GetByID(id int64) (bool, error) {\n\treturn isFound(DBConn.Where(\"id=?\", id).First(b))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/blockchain.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"time\"\n)\n\n// BlockChain is model\ntype BlockChain struct {\n\tID             int64  `gorm:\"primary_key;not_null\"`\n\tHash           []byte `gorm:\"not null\"`\n\tRollbacksHash  []byte `gorm:\"not null\"`\n\tData           []byte `gorm:\"not null\"`\n\tEcosystemID    int64  `gorm:\"not null\"`\n\tKeyID          int64  `gorm:\"not null\"`\n\tNodePosition   int64  `gorm:\"not null\"`\n\tTime           int64  `gorm:\"not null\"`\n\tTx             int32  `gorm:\"not null\"`\n\tConsensusMode  int32  `gorm:\"not null\"`\n\tCandidateNodes []byte `gorm:\"not null;default:null\"`\n}\n\n// TableName returns name of table\nfunc (BlockChain) TableName() string {\n\treturn \"block_chain\"\n}\n\n// Create is creating record of model\nfunc (b *BlockChain) Create(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Create(b).Error\n}\n\n// Get is retrieving model from database\nfunc (b *BlockChain) Get(blockID int64) (bool, error) {\n\treturn isFound(DBConn.Where(\"id = ?\", blockID).First(b))\n}\n\n// GetByHash is retrieving model from database\nfunc (b *BlockChain) GetByHash(BlockHash []byte) (bool, error) {\n\treturn isFound(DBConn.Where(\"hash = ?\", BlockHash).First(b))\n}\n\n// GetMaxBlock returns last block existence\nfunc (b *BlockChain) GetMaxBlock() (bool, error) {\n\treturn isFound(DBConn.Last(b))\n}\n\n// GetMaxForeignBlock returns last block generated not by key_id\nfunc (b *BlockChain) GetMaxForeignBlock(keyId int64) (bool, error) {\n\treturn isFound(DBConn.Order(\"id DESC\").Where(\"key_id != ?\", keyId).First(b))\n}\n\n// GetBlockchain is retrieving chain of blocks from database\nfunc GetBlockchain(startBlockID int64, endblockID int64, order ordering) ([]BlockChain, error) {\n\tvar err error\n\tblockchain := new([]BlockChain)\n\n\torderStr := \"id \" + string(order)\n\tquery := DBConn.Model(&BlockChain{}).Order(orderStr)\n\tif endblockID > 0 {\n\t\tquery = query.Where(\"id > ? AND id <= ?\", startBlockID, endblockID).Find(&blockchain)\n\t} else {\n\t\tquery = query.Where(\"id > ?\", startBlockID).Find(&blockchain)\n\t}\n\n\tif query.Error != nil {\n\t\treturn nil, err\n\t}\n\treturn *blockchain, nil\n}\n\n// GetBlocks is retrieving limited chain of blocks from database\nfunc (b *BlockChain) GetBlocks(startFromID int64, limit int) ([]BlockChain, error) {\n\tvar err error\n\tblockchain := new([]BlockChain)\n\tif startFromID > 0 {\n\t\terr = DBConn.Order(\"id desc\").Limit(limit).Where(\"id > ?\", startFromID).Find(&blockchain).Error\n\t} else {\n\t\terr = DBConn.Order(\"id desc\").Limit(limit).Find(&blockchain).Error\n\t}\n\treturn *blockchain, err\n}\n\n// GetBlocksFrom is retrieving ordered chain of blocks from database\nfunc (b *BlockChain) GetBlocksFrom(startFromID int64, ordering string, limit int) ([]BlockChain, error) {\n\tblockchain := new([]BlockChain)\n\tq := DBConn.Model(&BlockChain{}).Order(\"id \"+ordering).Where(\"id > ?\", startFromID)\n\tif limit > 0 {\n\t\tq = q.Limit(limit)\n\t}\n\terr := q.Find(&blockchain).Error\n\treturn *blockchain, err\n}\n\n// GetReverseBlockchain returns records of blocks in reverse ordering\nfunc (b *BlockChain) GetReverseBlockchain(endBlockID int64, limit int) ([]BlockChain, error) {\n\tvar err error\n\tblockchain := new([]BlockChain)\n\terr = DBConn.Model(&BlockChain{}).Order(\"id DESC\").Where(\"id <= ?\", endBlockID).Limit(limit).Find(&blockchain).Error\n\treturn *blockchain, err\n}\n\n// GetNodeBlocksAtTime returns records of blocks for time interval and position of node\nfunc (b *BlockChain) GetNodeBlocksAtTime(from, to time.Time, node int64) ([]BlockChain, error) {\n\tvar err error\n\tblockchain := new([]BlockChain)\n\terr = DBConn.Model(&BlockChain{}).Where(\"node_position = ? AND time BETWEEN ? AND ?\", node, from.Unix(), to.Unix()).Find(&blockchain).Error\n\treturn *blockchain, err\n}\n\n// DeleteById is deleting block by ID\nfunc (b *BlockChain) DeleteById(dbTx *DbTransaction, id int64) error {\n\treturn GetDB(dbTx).Where(\"id = ?\", id).Delete(BlockChain{}).Error\n}\n\nfunc GetTxCount() (int64, error) {\n\tvar txCount int64\n\trow := DBConn.Raw(\"SELECT SUM(tx) tx_count FROM block_chain\").Select(\"tx_count\").Row()\n\terr := row.Scan(&txCount)\n\n\treturn txCount, err\n}\n\nfunc GetBlockCountByNode(NodePosition int64, consensusMode int32) (int64, error) {\n\tvar BlockCount int64\n\trow := DBConn.Raw(\"SELECT count(*) block_count FROM block_chain where node_Position = ? AND consensus_mode = ?\",\n\t\tNodePosition, consensusMode).Select(\"block_count\").Row()\n\terr := row.Scan(&BlockCount)\n\n\treturn BlockCount, err\n}\nfunc (b *BlockChain) GetRecentBlockChain(startBlockId int64, maxBlockId int64) ([]BlockChain, error) {\n\tblockchain := new([]BlockChain)\n\terr := DBConn.Where(\"id > ? and id <= ?\", startBlockId, maxBlockId).Find(&blockchain).Error\n\n\treturn *blockchain, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/candidate_node.go",
    "content": "package sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/shopspring/decimal\"\n)\n\ntype CandidateNode struct {\n\tID              int64           `gorm:\"column:id\" json:\"id\"`\n\tApiAddress      string          `gorm:\"column:api_address\" json:\"apiAddress\"`\n\tTcpAddress      string          `gorm:\"column:tcp_address\" json:\"tcpAddress\"`\n\tNodePubKey      string          `gorm:\"column:node_pub_key\" json:\"nodePubKey\"`\n\tDateCreated     int64           `gorm:\"column:date_created\" json:\"dateCreated\"`\n\tDeleted         uint8           `gorm:\"column:deleted\" json:\"deleted\"`\n\tDateDeleted     int64           `gorm:\"column:date_deleted\" json:\"dateDeleted\"`\n\tWebsite         string          `gorm:\"column:website\" json:\"website\"`\n\tReplyCount      int64           `gorm:\"column:reply_count\" json:\"replyCount\"`\n\tDateReply       int64           `gorm:\"column:date_reply\" json:\"dateReply\"`\n\tEarnestTotal    decimal.Decimal `gorm:\"column:earnest_total\" json:\"earnestTotal\"`\n\tNodeName        string          `gorm:\"column:node_name\" json:\"nodeName\"`\n\tReferendumTotal decimal.Decimal `gorm:\"column:referendum_total\" json:\"referendumTotal\"`\n\tCandidateNodes  []byte          `json:\"candidateNodes\"`\n}\n\ntype CandidateNodes []CandidateNode\n\nfunc (nodes CandidateNodes) Len() int {\n\treturn len(nodes)\n}\nfunc (nodes CandidateNodes) Swap(i, j int) {\n\tnodes[i], nodes[j] = nodes[j], nodes[i]\n}\n\nfunc (nodes CandidateNodes) Less(i, j int) bool {\n\treturn nodes[i].DateReply > nodes[j].DateReply\n}\n\n// TableName returns name of table\nfunc (ib *CandidateNode) TableName() string {\n\treturn \"1_candidate_node_requests\"\n}\n\n// GetCandidateNode returns last good block\nfunc GetCandidateNode(numberOfNodes int) (CandidateNodes, error) {\n\tvar candidateNodes CandidateNodes\n\tpledgeAmount, err := GetPledgeAmount()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = GetDB(nil).Where(\"deleted = ? and earnest_total >= ?\", 0, pledgeAmount).Order(\"referendum_total desc,date_updated_referendum asc,reply_count desc,date_reply desc\").Limit(numberOfNodes).Find(&candidateNodes).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn candidateNodes, nil\n}\n\nfunc (c *CandidateNode) UpdateCandidateNodeInfo() error {\n\tpledgeAmount, err := GetPledgeAmount()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = GetDB(nil).Model(&c).Where(\"tcp_address = ? and deleted = ? and earnest_total >= ?\", c.TcpAddress, 0, pledgeAmount).Updates(CandidateNode{ReplyCount: c.ReplyCount, DateReply: c.DateReply, CandidateNodes: c.CandidateNodes}).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (c *CandidateNode) GetCandidateNodeByAddress(tcpAddress string) error {\n\tpledgeAmount, err := GetPledgeAmount()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = GetDB(nil).Where(\"tcp_address = ? and deleted = ? and earnest_total >= ?\", tcpAddress, 0, pledgeAmount).Find(&c).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (c *CandidateNode) GetCandidateNodeByPublicKey(nodePublicKey string) error {\n\tpledgeAmount, err := GetPledgeAmount()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = GetDB(nil).Where(\"node_pub_key = ? and deleted = ? and earnest_total >= ?\", nodePublicKey, 0, pledgeAmount).Find(&c).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (c *CandidateNode) GetCandidateNodeById(id int64) error {\n\tpledgeAmount, err := GetPledgeAmount()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = GetDB(nil).Where(\"id = ? and deleted = ? and earnest_total >= ?\", id, 0, pledgeAmount).First(&c).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc GetPledgeAmount() (int64, error) {\n\tvar (\n\t\tpledgeAmount string\n\t\terr          error\n\t\tamount       decimal.Decimal\n\t)\n\trow := DBConn.Raw(`select\n\t\t\t\t\t\t\t\tap.value \n\t\t\t\t\t\t\tfrom\n\t\t\t\t\t\t\t\t\"1_app_params\" ap,\n\t\t\t\t\t\t\t\t\"1_applications\" a\n\t\t\t\t\t\t\twhere\n\t\t\t\t\t\t\t\tap.app_id = a.id\n\t\t\t\t\t\t\t\tand a.\"name\" = 'CandidateNode'\n\t\t\t\t\t\t\t\tand ap.\"name\" = 'limit_candidate_pack'\n\t\t\t\t\t\t\t\tand a.deleted = 0\n\t\t\t\t\t\t\t\tand a.ecosystem = 1`).Row()\n\terr = row.Scan(&pledgeAmount)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tamount, err = decimal.NewFromString(pledgeAmount)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn amount.Mul(decimal.New(1, consts.MoneyDigits)).IntPart(), nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/confirmations.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\n// Confirmation is model\ntype Confirmation struct {\n\tBlockID int64 `gorm:\"primary_key\"`\n\tGood    int32 `gorm:\"not null\"`\n\tBad     int32 `gorm:\"not null\"`\n\tTime    int64 `gorm:\"not null\"`\n}\n\n// GetGoodBlock returns last good block\nfunc (c *Confirmation) GetGoodBlock(goodCount int) (bool, error) {\n\treturn isFound(DBConn.Where(\"good >= ?\", goodCount).Last(&c))\n}\n\n// GetConfirmation returns if block with blockID exists\nfunc (c *Confirmation) GetConfirmation(blockID int64) (bool, error) {\n\treturn isFound(DBConn.Where(\"block_id= ?\", blockID).First(&c))\n}\n\n// Save is saving model\nfunc (c *Confirmation) Save() error {\n\treturn DBConn.Save(c).Error\n}\n\n// GetGoodBlockLast returns last good block\nfunc (c *Confirmation) GetGoodBlockLast() (bool, error) {\n\tvar sp PlatformParameter\n\tcount, err := sp.GetNumberOfHonorNodes()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn isFound(DBConn.Where(\"good >= ?\", int(count/2)).Last(&c))\n}\n\n// GetGoodBlock returns last good block\nfunc (c *Confirmation) CheckAllowGenBlock() (bool, error) {\n\tprevBlock := &InfoBlock{}\n\t_, err := prevBlock.Get()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tvar sp PlatformParameter\n\tcount, err := sp.GetNumberOfHonorNodes()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif count == 0 {\n\t\treturn true, nil\n\t}\n\n\tf, err := c.GetGoodBlock(count / 2)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif f {\n\t\tif prevBlock.BlockID-c.BlockID < 1 {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/contract.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport \"github.com/IBAX-io/go-ibax/packages/converter\"\n\n// Contract represents record of 1_contracts table\ntype Contract struct {\n\tID          int64  `json:\"id,omitempty\"`\n\tName        string `json:\"name,omitempty\"`\n\tValue       string `json:\"value,omitempty\"`\n\tWalletID    int64  `json:\"wallet_id,omitempty\"`\n\tActive      bool   `json:\"active,omitempty\"`\n\tTokenID     int64  `json:\"token_id,omitempty\"`\n\tConditions  string `json:\"conditions,omitempty\"`\n\tAppID       int64  `json:\"app_id,omitempty\"`\n\tEcosystemID int64  `gorm:\"column:ecosystem\" json:\"ecosystem_id,omitempty\"`\n}\n\n// TableName returns name of table\nfunc (c *Contract) TableName() string {\n\treturn `1_contracts`\n}\n\n// Get is retrieving id contracts from database\nfunc (c *Contract) Get(Id int64) (bool, error) {\n\treturn isFound(DBConn.Where(\"id = ?\", Id).First(c))\n}\n\n// GetList is retrieving records from database\nfunc (c *Contract) GetList(offset, limit int) ([]Contract, error) {\n\tresult := new([]Contract)\n\terr := DBConn.Table(c.TableName()).Offset(offset).Limit(limit).Order(\"id asc\").Find(&result).Error\n\treturn *result, err\n}\n\n// GetFromEcosystem retrieving ecosystem contracts from database\nfunc (c *Contract) GetFromEcosystem(db *DbTransaction, ecosystem int64) ([]Contract, error) {\n\tresult := new([]Contract)\n\terr := GetDB(db).Table(c.TableName()).Where(\"ecosystem = ?\", ecosystem).Order(\"id asc\").Find(&result).Error\n\treturn *result, err\n}\n\n// Count returns count of records in table\nfunc (c *Contract) Count(db *DbTransaction) (count int64, err error) {\n\terr = GetDB(db).Table(c.TableName()).Count(&count).Error\n\treturn\n}\n\nfunc (c *Contract) GetListByEcosystem(offset, limit int) ([]Contract, error) {\n\tvar list []Contract\n\terr := DBConn.Table(c.TableName()).Offset(offset).Limit(limit).\n\t\tOrder(\"id asc\").Where(\"ecosystem = ?\", c.EcosystemID).\n\t\tFind(&list).Error\n\treturn list, err\n}\n\nfunc (c *Contract) CountByEcosystem() (n int64, err error) {\n\terr = DBConn.Table(c.TableName()).Where(\"ecosystem = ?\", c.EcosystemID).Count(&n).Error\n\treturn\n}\n\nfunc (c *Contract) ToMap() (v map[string]string) {\n\tv = make(map[string]string)\n\tv[\"id\"] = converter.Int64ToStr(c.ID)\n\tv[\"name\"] = c.Name\n\tv[\"value\"] = c.Value\n\tv[\"wallet_id\"] = converter.Int64ToStr(c.WalletID)\n\tv[\"token_id\"] = converter.Int64ToStr(c.TokenID)\n\tv[\"conditions\"] = c.Conditions\n\tv[\"app_id\"] = converter.Int64ToStr(c.AppID)\n\tv[\"ecosystem_id\"] = converter.Int64ToStr(c.EcosystemID)\n\treturn\n}\n\n// GetByApp returns all contracts belonging to selected app\nfunc (c *Contract) GetByApp(appID int64, ecosystemID int64) ([]Contract, error) {\n\tvar result []Contract\n\terr := DBConn.Select(\"id, name\").Where(\"app_id = ? and ecosystem = ?\", appID, ecosystemID).Find(&result).Error\n\treturn result, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/cron.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"fmt\"\n)\n\n// Cron represents record of {prefix}_cron table\ntype Cron struct {\n\ttableName string\n\tID        int64\n\tCron      string\n\tContract  string\n}\n\n// SetTablePrefix is setting table prefix\nfunc (c *Cron) SetTablePrefix(prefix string) {\n\tc.tableName = prefix + \"_cron\"\n}\n\n// TableName returns name of table\nfunc (c *Cron) TableName() string {\n\treturn c.tableName\n}\n\n// Get is retrieving model from database\nfunc (c *Cron) Get(id int64) (bool, error) {\n\treturn isFound(DBConn.Where(\"id = ?\", id).First(c))\n}\n\n// GetAllCronTasks is returning all cron tasks\nfunc (c *Cron) GetAllCronTasks() ([]*Cron, error) {\n\tvar crons []*Cron\n\terr := DBConn.Table(c.TableName()).Find(&crons).Error\n\treturn crons, err\n}\n\n// UID returns unique identifier for cron task\nfunc (c *Cron) UID() string {\n\treturn fmt.Sprintf(\"%s_%d\", c.tableName, c.ID)\n}\n"
  },
  {
    "path": "packages/storage/sqldb/database.go",
    "content": "package sqldb\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"gorm.io/gorm\"\n)\n\nfunc GetNodeRows(tableName string) (int64, error) {\n\tvar count int64\n\terr := DBConn.Table(tableName).Count(&count).Error\n\tif err == gorm.ErrRecordNotFound {\n\t\treturn 0, nil\n\t}\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn count, nil\n}\n\nfunc GetRowsInfo(rows *sql.Rows, sqlQuest string) ([]map[string]any, error) {\n\tvar result []map[string]any\n\tdefer rows.Close()\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn result, fmt.Errorf(\"getrows Columns err:%s in query %s\", err, sqlQuest)\n\t}\n\tvalues := make([]any, len(columns))\n\tscanArgs := make([]any, len(values))\n\tfor i := range values {\n\t\tscanArgs[i] = &values[i]\n\t}\n\tfor rows.Next() {\n\t\terr = rows.Scan(scanArgs...)\n\t\tif err != nil {\n\t\t\treturn result, fmt.Errorf(\"getRows scan err:%s in query %s\", err, sqlQuest)\n\t\t}\n\t\tvar value any\n\t\trez := make(map[string]any)\n\t\tfor i, col := range values {\n\t\t\t// Here we can check if the value is nil (NULL value)\n\t\t\tif col == nil {\n\t\t\t\tvalue = \"NULL\"\n\t\t\t} else {\n\t\t\t\tvalue = col\n\t\t\t}\n\t\t\trez[columns[i]] = value\n\t\t}\n\t\tresult = append(result, rez)\n\n\t}\n\tif err = rows.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"getRows rows err:%s in query %s\", err, sqlQuest)\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/db.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/kvdb/redis\"\n\n\t\"gorm.io/driver/postgres\"\n\t\"gorm.io/gorm\"\n\t\"gorm.io/gorm/logger\"\n)\n\nvar (\n\t// DBConn is orm connection\n\tDBConn *gorm.DB\n\n\t// ErrRecordNotFound is Not Found Record wrapper\n\tErrRecordNotFound = gorm.ErrRecordNotFound\n\n\t// ErrDBConn database connection error\n\tErrDBConn = errors.New(\"database connection error\")\n)\nvar notAutoIncrement = map[string]bool{\n\t\"1_keys\": true,\n}\n\n// non-self-increasing costs\nconst notAutoIncrementCost int64 = 1\n\ntype KeyTableChecker struct{}\n\nfunc (ktc KeyTableChecker) IsKeyTable(tableName string) bool {\n\tval, exist := converter.FirstEcosystemTables[tableName]\n\treturn exist && val\n}\n\ntype NextIDGetter struct {\n\tTx *DbTransaction\n}\n\nfunc (g NextIDGetter) GetNextID(tableName string) (int64, error) {\n\treturn g.Tx.GetNextID(tableName)\n}\nfunc isFound(db *gorm.DB) (bool, error) {\n\tif errors.Is(db.Error, ErrRecordNotFound) {\n\t\treturn false, nil\n\t}\n\treturn true, db.Error\n}\n\n// InitDB drop all tables and exec db schema\nfunc InitDB(cfg conf.DBConfig) error {\n\terr := GormInit(cfg)\n\tif err != nil || DBConn == nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"initializing DB\")\n\t\treturn ErrDBConn\n\t}\n\tif err = NewDbTransaction(DBConn).DropTables(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"dropping all tables\")\n\t\treturn err\n\t}\n\n\tif conf.Config.Redis.Enable {\n\t\terr = redis.RedisInit(conf.Config.Redis)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\n\t\t\t\t\"host\": conf.Config.Redis.Host, \"port\": conf.Config.Redis.Port, \"db_password\": conf.Config.Redis.Password, \"db_name\": conf.Config.Redis.DbName, \"type\": consts.DBError,\n\t\t\t}).Error(\"can't init redis\")\n\t\t\treturn err\n\t\t}\n\n\t\tvar rd redis.RedisParams\n\t\terr := rd.Cleardb()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t}\n\n\tif err = ExecSchema(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing db schema\")\n\t\treturn err\n\t}\n\n\tinstall := &Install{Progress: ProgressComplete}\n\tif err = install.Create(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating install\")\n\t\treturn err\n\t}\n\n\tif err := ExecCLBSchema(consts.DefaultCLB, conf.Config.KeyID); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating CLB schema\")\n\t\treturn err\n\t}\n\tif err := ExecSubSchema(); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating CLB schema\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// GormInit is initializes Gorm connection\nfunc GormInit(conf conf.DBConfig) error {\n\tvar err error\n\tdsn := fmt.Sprintf(\"host=%s port=%d user=%s dbname=%s sslmode=disable password=%s TimeZone=UTC\", conf.Host, conf.Port, conf.User, conf.Name, conf.Password)\nopen:\n\tDBConn, err = gorm.Open(postgres.New(postgres.Config{\n\t\tDSN:                  dsn,\n\t\tPreferSimpleProtocol: true, // disables implicit prepared statement usage\n\t}), &gorm.Config{\n\t\tAllowGlobalUpdate: true, //allow global update\n\t\t//PrepareStmt:       true,\n\t\tLogger: logger.Default.LogMode(logger.Silent), // start Logger, show detail log\n\t})\n\t//DBConn, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"SQLSTATE 3D000\") {\n\t\t\terr := createDatabase(fmt.Sprintf(\"host=%s port=%d user=%s password=%s sslmode=disable TimeZone=UTC\", conf.Host, conf.Port, conf.User, conf.Password), conf.Name)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tgoto open\n\t\t}\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"cant open connection to DB\")\n\t\tDBConn = nil\n\t\treturn err\n\t}\n\tsqlDB, err := DBConn.DB()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"cant get sql DB\")\n\t\tDBConn = nil\n\t\treturn err\n\t}\n\n\tsqlDB.SetConnMaxLifetime(time.Minute * 10)\n\tsqlDB.SetMaxIdleConns(conf.MaxIdleConns)\n\tsqlDB.SetMaxOpenConns(conf.MaxOpenConns)\n\n\tif err = setupConnOptions(DBConn); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc createDatabase(dsn string, dbName string) error {\n\tdb, err := gorm.Open(postgres.Open(dsn), &gorm.Config{\n\t\tLogger: logger.Default.LogMode(logger.Error),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tresult := db.Exec(\"create database \" + dbName)\n\tdefer func() {\n\t\td, _ := db.DB()\n\t\td.Close()\n\t}()\n\treturn result.Error\n}\n\nfunc setupConnOptions(conr *gorm.DB) error {\n\tif err := conr.Exec(fmt.Sprintf(`set lock_timeout = %d;`, conf.Config.DB.LockTimeout)).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"can't set lock timeout\")\n\t\treturn err\n\t}\n\n\tif err := conr.Exec(fmt.Sprintf(`set idle_in_transaction_session_timeout = %d;`, conf.Config.DB.IdleInTxTimeout)).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"can't set idle_in_transaction_session_timeout\")\n\t\treturn err\n\t}\n\treturn conr.Exec(\"SET TIME ZONE 'UTC'\").Error\n}\n\n// GormClose is closing Gorm connection\nfunc GormClose() error {\n\tif DBConn != nil {\n\t\tsqlDB, err := DBConn.DB()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = sqlDB.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tDBConn = nil\n\t}\n\treturn nil\n}\n\n// DbTransaction is gorm.DB wrapper\ntype DbTransaction struct {\n\tconn      *gorm.DB\n\tBinLogSql [][]byte\n}\n\nfunc NewDbTransaction(conn *gorm.DB) *DbTransaction {\n\treturn &DbTransaction{conn: conn}\n}\n\nfunc (d *DbTransaction) Debug() *DbTransaction {\n\td.conn = d.conn.Debug()\n\treturn d\n}\n\n// StartTransaction is beginning transaction\nfunc StartTransaction() (*DbTransaction, error) {\n\tconn := DBConn.Begin()\n\tif conn.Error != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": conn.Error}).Error(\"cannot start transaction because of connection error\")\n\t\treturn nil, conn.Error\n\t}\n\n\tif err := setupConnOptions(conn); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &DbTransaction{\n\t\tconn: conn,\n\t}, nil\n}\n\n// Rollback is transaction rollback\nfunc (tr *DbTransaction) Rollback() error {\n\treturn tr.conn.Rollback().Error\n}\n\n// Commit is transaction commit\nfunc (tr *DbTransaction) Commit() error {\n\treturn tr.conn.Commit().Error\n}\n\n// Connection returns connection of database\nfunc (tr *DbTransaction) Connection() *gorm.DB {\n\treturn tr.conn\n}\n\n// Savepoint creates PostgreSQL Savepoint\nfunc (tr *DbTransaction) Savepoint(mark string) error {\n\treturn tr.Connection().SavePoint(mark).Error\n}\n\n// RollbackSavepoint rollbacks PostgreSQL Savepoint\nfunc (tr *DbTransaction) RollbackSavepoint(mark string) error {\n\treturn tr.Connection().RollbackTo(mark).Error\n}\n\nfunc (tr *DbTransaction) ResetSavepoint(mark string) error {\n\tif err := tr.RollbackSavepoint(mark); err != nil {\n\t\treturn err\n\t}\n\treturn tr.Savepoint(mark)\n}\n\n// GetDB is returning gorm.DB\nfunc GetDB(tr *DbTransaction) *gorm.DB {\n\tif tr != nil && tr.conn != nil {\n\t\treturn tr.conn\n\t}\n\treturn DBConn\n}\n\n// DropTables is dropping all of the tables\nfunc (dbTx *DbTransaction) DropTables() error {\n\treturn GetDB(dbTx).Exec(`\n\tDO $$ DECLARE\n\t    r RECORD;\n\tBEGIN\n\t    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP\n\t\tEXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';\n\t    END LOOP;\n\tEND $$;\n\t`).Error\n}\n\n// GetRecordsCountTx is counting all records of table in transaction\nfunc (dbTx *DbTransaction) GetRecordsCountTx(tableName, where string) (count int64, err error) {\n\tdbQuery := GetDB(dbTx).Table(tableName)\n\tif len(where) > 0 {\n\t\tdbQuery = dbQuery.Where(where)\n\t}\n\tif !notAutoIncrement[tableName] {\n\t\terr := dbQuery.Select(\"id\").Order(\"id DESC\").Limit(1).Scan(&count).Error\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t} else {\n\t\t//err = dbQuery.Count(&count).Error\n\t\tcount = notAutoIncrementCost\n\t}\n\treturn count, err\n}\n\n// Update is updating table rows\nfunc (dbTx *DbTransaction) Update(tblname, set, where string) error {\n\tsql := `UPDATE \"` + strings.Trim(tblname, `\"`) + `\" SET ` + set + \" \" + where\n\treturn dbTx.ExecSql(sql)\n}\n\n// ExecSql is exec sql\nfunc (dbTx *DbTransaction) ExecSql(sql string) error {\n\tqueryFn := func(tx *gorm.DB) *gorm.DB {\n\t\treturn tx.Exec(sql)\n\t}\n\terr := queryFn(GetDB(dbTx)).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\tdbTx.BinLogSql = append(dbTx.BinLogSql, []byte(sql))\n\treturn nil\n}\n\n// Delete is deleting table rows\nfunc (dbTx *DbTransaction) Delete(tblname, where string) error {\n\treturn dbTx.ExecSql(`DELETE FROM \"` + tblname + `\" ` + where)\n}\n\n// GetColumnCount is counting rows in table\nfunc (dbTx *DbTransaction) GetColumnCount(tableName string) (int64, error) {\n\tvar count int64\n\terr := GetDB(dbTx).Raw(\"SELECT count(*) FROM information_schema.columns WHERE table_name=?\", tableName).Row().Scan(&count)\n\tif err == gorm.ErrRecordNotFound {\n\t\treturn 0, nil\n\t}\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing raw query\")\n\t\treturn 0, err\n\t}\n\treturn count, nil\n}\n\n// AlterTableAddColumn is adding column to table\nfunc (dbTx *DbTransaction) AlterTableAddColumn(tableName, columnName, columnType string) error {\n\treturn dbTx.ExecSql(`ALTER TABLE \"` + tableName + `\" ADD COLUMN \"` + columnName + `\" ` + columnType)\n}\n\n// AlterTableDropColumn is dropping column from table\nfunc (dbTx *DbTransaction) AlterTableDropColumn(tableName, columnName string) error {\n\treturn dbTx.ExecSql(`ALTER TABLE \"` + tableName + `\" DROP COLUMN \"` + columnName + `\"`)\n}\n\n// CreateIndex is creating index on table column\nfunc (dbTx *DbTransaction) CreateIndex(indexName, tableName, onColumn string) error {\n\treturn GetDB(dbTx).Exec(`CREATE INDEX \"` + indexName + `_index\" ON \"` + tableName + `\" (` + onColumn + `)`).Error\n}\n\n// GetColumnDataTypeCharMaxLength is returns max length of table column\nfunc (dbTx *DbTransaction) GetColumnDataTypeCharMaxLength(tableName, columnName string) (map[string]string, error) {\n\treturn dbTx.GetOneRow(`select data_type,character_maximum_length from\n\t\t\t information_schema.columns where table_name = ? AND column_name = ?`,\n\t\ttableName, columnName).String()\n}\n\n// GetAllColumnTypes returns column types for table\nfunc (dbTx *DbTransaction) GetAllColumnTypes(tblname string) ([]map[string]string, error) {\n\treturn dbTx.GetAllTransaction(`SELECT column_name, data_type\n\t\tFROM information_schema.columns\n\t\tWHERE table_name = ?\n\t\tORDER BY ordinal_position ASC`, -1, tblname)\n}\n\nfunc DataTypeToColumnType(dataType string) string {\n\tvar itype string\n\tswitch {\n\tcase dataType == \"character varying\":\n\t\titype = `varchar`\n\tcase dataType == `bigint`:\n\t\titype = \"number\"\n\tcase dataType == `jsonb`:\n\t\titype = \"json\"\n\tcase strings.HasPrefix(dataType, `timestamp`):\n\t\titype = \"datetime\"\n\tcase strings.HasPrefix(dataType, `numeric`):\n\t\titype = \"money\"\n\tcase strings.HasPrefix(dataType, `double`):\n\t\titype = \"double\"\n\tcase strings.HasPrefix(dataType, `bytea`):\n\t\titype = \"bytea\"\n\tdefault:\n\t\titype = dataType\n\t}\n\treturn itype\n}\n\n// GetColumnType is returns type of column\nfunc (dbTx *DbTransaction) GetColumnType(tblname, column string) (itype string, err error) {\n\tcoltype, err := dbTx.GetColumnDataTypeCharMaxLength(tblname, column)\n\tif err != nil {\n\t\treturn\n\t}\n\tif dataType, ok := coltype[\"data_type\"]; ok {\n\t\titype = DataTypeToColumnType(dataType)\n\t}\n\treturn\n}\n\n// DropTable is dropping table\nfunc (dbTx *DbTransaction) DropTable(tableName string) error {\n\treturn GetDB(dbTx).Migrator().DropTable(tableName)\n}\n\n// NumIndexes is counting table indexes\nfunc (dbTx *DbTransaction) NumIndexes(tblname string) (int, error) {\n\tvar indexes int64\n\terr := GetDB(dbTx).Raw(fmt.Sprintf(`select count( i.relname) from pg_class t, pg_class i, pg_index ix, pg_attribute a\n\t where t.oid = ix.indrelid and i.oid = ix.indexrelid and a.attrelid = t.oid and a.attnum = ANY(ix.indkey)\n         and t.relkind = 'r'  and t.relname = '%s'`, tblname)).Row().Scan(&indexes)\n\tif err == gorm.ErrRecordNotFound {\n\t\treturn 0, nil\n\t}\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int(indexes - 1), nil\n}\n\n// IsIndex returns is table column is an index\nfunc (dbTx *DbTransaction) IsIndex(tblname, column string) (bool, error) {\n\trow, err := dbTx.GetOneRow(`select t.relname as table_name, i.relname as index_name, a.attname as column_name\n\t from pg_class t, pg_class i, pg_index ix, pg_attribute a \n\t where t.oid = ix.indrelid and i.oid = ix.indexrelid and a.attrelid = t.oid and a.attnum = ANY(ix.indkey)\n\t\t and t.relkind = 'r'  and t.relname = ?  and a.attname = ?`, tblname, column).String()\n\treturn len(row) > 0 && row[`column_name`] == column, err\n}\n\n// GetNextID returns next ID of table\nfunc (dbTx *DbTransaction) GetNextID(table string) (int64, error) {\n\tvar id int64\n\trows, err := GetDB(dbTx).Raw(`select id from \"` + table + `\" order by id desc limit 1`).Rows()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": table}).Error(\"selecting next id from table\")\n\t\treturn 0, err\n\t}\n\trows.Next()\n\trows.Scan(&id)\n\trows.Close()\n\treturn id + 1, err\n}\n\n// IsTable returns is table exists\nfunc (dbTx *DbTransaction) IsTable(tblname string) bool {\n\tvar name string\n\terr := GetDB(dbTx).Table(\"information_schema.tables\").\n\t\tWhere(\"table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema') AND table_name=?\", tblname).\n\t\tSelect(\"table_name\").Row().Scan(&name)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn name == tblname\n}\n\nfunc (dbTx *DbTransaction) HasTableOrView(names string) bool {\n\tvar name string\n\tGetDB(dbTx).Table(\"information_schema.tables\").\n\t\tWhere(\"table_type IN ('BASE TABLE', 'VIEW') AND table_schema NOT IN ('pg_catalog', 'information_schema') AND table_name=?\", names).\n\t\tSelect(\"table_name\").Row().Scan(&name)\n\n\treturn name == names\n}\n\n// GetColumnByID returns the value of the column from the table by id\nfunc GetColumnByID(table, column string, id int64) (result string, err error) {\n\tdbTr := new(DbTransaction)\n\tcolumnList, err := dbTr.GetAllColumnTypes(table)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tvar exist bool\n\tfor _, list := range columnList {\n\t\tfor k, v := range list {\n\t\t\tif k == \"column_name\" {\n\t\t\t\tif v == column {\n\t\t\t\t\texist = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif exist {\n\t\t\tbreak\n\t\t}\n\t}\n\tif !exist {\n\t\treturn \"\", errors.New(\"column invalid\")\n\t}\n\n\terr = GetDB(nil).Table(table).Select(column).Where(\"id=?\", id).Row().Scan(&result)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting column by id\")\n\t}\n\treturn\n}\n\n// DropDatabase kill all process and drop database\nfunc (dbTx *DbTransaction) DropDatabase(name string) error {\n\tquery := `SELECT\n\tpg_terminate_backend (pg_stat_activity.pid)\n   FROM\n\tpg_stat_activity\n   WHERE\n\tpg_stat_activity.datname = ?`\n\n\tif err := GetDB(dbTx).Exec(query, name).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"dbname\": name}).Error(\"on kill db process\")\n\t\treturn err\n\t}\n\n\tif err := GetDB(dbTx).Exec(fmt.Sprintf(\"DROP DATABASE IF EXISTS %s\", name)).Error; err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"dbname\": name}).Error(\"on drop db\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// GetSumColumn returns the value of the column from the table by id\nfunc (dbTx *DbTransaction) GetSumColumn(table, column, where string) (result string, err error) {\n\terr = GetDB(dbTx).Table(table).Select(\"sum(\" + column + \")\").Where(where).Row().Scan(&result)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"sum column\")\n\t}\n\treturn\n}\n\n// GetSumColumnCount returns the value of the column from the table by id\nfunc (dbTx *DbTransaction) GetSumColumnCount(table, column, where string) (result int, err error) {\n\terr = GetDB(dbTx).Table(table).Select(\"count(*)\").Where(where).Row().Scan(&result)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"sum column\")\n\t}\n\treturn\n}\n\ntype Namer struct {\n\tTableType string\n}\n\ntype SchemaInter interface {\n\tHasExists(tr *DbTransaction, name string) bool\n}\n\nfunc (v Namer) HasExists(tr *DbTransaction, names string) bool {\n\tvar typs string\n\tswitch v.TableType {\n\tcase \"table\":\n\t\ttyps = `= 'BASE TABLE'`\n\tcase \"view\":\n\t\ttyps = `= 'VIEW'`\n\tdefault:\n\t\ttyps = `IN ('BASE TABLE', 'VIEW')`\n\t}\n\tvar name string\n\tGetDB(tr).Table(\"information_schema.tables\").\n\t\tWhere(fmt.Sprintf(\"table_type %s AND table_schema NOT IN ('pg_catalog', 'information_schema') AND table_name='%s'\", typs, names)).\n\t\tSelect(\"table_name\").Row().Scan(&name)\n\treturn name == names\n}\n"
  },
  {
    "path": "packages/storage/sqldb/delayed_contract.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nconst tableDelayedContracts = \"1_delayed_contracts\"\nconst availableDelayedContracts = 0\n\n// DelayedContract represents record of 1_delayed_contracts table\ntype DelayedContract struct {\n\tID         int64  `gorm:\"primary_key;not null\"`\n\tContract   string `gorm:\"not null\"`\n\tKeyID      int64  `gorm:\"not null\"`\n\tBlockID    int64  `gorm:\"not null\"`\n\tEveryBlock int64  `gorm:\"not null\"`\n\tCounter    int64  `gorm:\"not null\"`\n\tHighRate   int64  `gorm:\"not null\"`\n\tLimit      int64  `gorm:\"not null\"`\n\tDelete     bool   `gorm:\"not null\"`\n\tConditions string `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (DelayedContract) TableName() string {\n\treturn tableDelayedContracts\n}\n\n// GetAllDelayedContractsForBlockID returns contracts that want to execute for blockID\nfunc GetAllDelayedContractsForBlockID(blockID int64) ([]*DelayedContract, error) {\n\tvar contracts []*DelayedContract\n\tif err := DBConn.Where(`block_id <= ? AND ?%every_block = 0 AND deleted = ? AND (counter < \"1_delayed_contracts\".limit OR \"1_delayed_contracts\".limit = 0)`,\n\t\tblockID, blockID, availableDelayedContracts).Order(\"high_rate desc\").Find(&contracts).Error; err != nil {\n\t\treturn nil, err\n\t}\n\treturn contracts, nil\n}\n\n// Get is retrieving model from database\nfunc (dc *DelayedContract) Get(id int64) (bool, error) {\n\treturn isFound(DBConn.Where(\"id = ?\", id).First(dc))\n}\n\n// GetByContract is retrieving model by contract from database\nfunc (dc *DelayedContract) GetByContract(dbTx *DbTransaction, contract string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"contract = ? AND deleted = ?\", contract, availableDelayedContracts).First(dc))\n}\n\nfunc GetAllDelayedContract() ([]*DelayedContract, error) {\n\tvar contracts []*DelayedContract\n\tif err := DBConn.Where(\" deleted = ?\", availableDelayedContracts).Find(&contracts).Error; err != nil {\n\t\treturn nil, err\n\t}\n\treturn contracts, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/ecosystem.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/pkg/errors\"\n)\n\nconst ecosysTable = \"1_ecosystems\"\n\n// Ecosystem is model\ntype Ecosystem struct {\n\tID             int64 `gorm:\"primary_key;not null\"`\n\tName           string\n\tIsValued       bool\n\tEmissionAmount string `gorm:\"type:jsonb\"`\n\tTokenSymbol    string\n\tTokenName      string\n\tTypeEmission   int64\n\tTypeWithdraw   int64\n\tDigits         int64\n\tInfo           string `gorm:\"type:jsonb\"`\n\tFeeModeInfo    string `json:\"fee_mode_info\" gorm:\"type:jsonb\"`\n}\n\ntype FeeModeFlag struct {\n\tFlag           string `json:\"flag\"`\n\tConversionRate string `json:\"conversion_rate\"`\n}\n\ntype EcoParam struct {\n\tId      int64\n\tPercent int64\n\tDigits  int\n}\n\nfunc (f FeeModeFlag) FlagToInt() int64 {\n\tret, _ := strconv.ParseInt(f.Flag, 10, 64)\n\treturn ret\n\n}\n\nfunc (f FeeModeFlag) ConversionRateToFloat() float64 {\n\tret, _ := strconv.ParseFloat(f.ConversionRate, 64)\n\treturn ret\n}\n\ntype Combustion struct {\n\tFlag    int64 `json:\"flag\"`\n\tPercent int64 `json:\"percent\"`\n}\n\ntype FeeModeInfo struct {\n\tFeeModeDetail map[string]FeeModeFlag `json:\"fee_mode_detail\"`\n\tCombustion    Combustion             `json:\"combustion\"`\n\tFollowFuel    float64                `json:\"follow_fuel\"`\n}\n\n// TableName returns name of table\n// only first ecosystem has this entity\nfunc (sys *Ecosystem) TableName() string {\n\treturn ecosysTable\n}\n\n// GetAllSystemStatesIDs is retrieving all ecosystems ids\nfunc GetAllSystemStatesIDs() ([]int64, []string, error) {\n\tif !NewDbTransaction(DBConn).IsTable(ecosysTable) {\n\t\treturn nil, nil, nil\n\t}\n\n\tecosystems := new([]Ecosystem)\n\tif err := DBConn.Select(\"id,name\").Order(\"id asc\").Find(&ecosystems).Error; err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tids := make([]int64, len(*ecosystems))\n\tnames := make([]string, len(*ecosystems))\n\tfor i, s := range *ecosystems {\n\t\tids[i] = s.ID\n\t\tnames[i] = s.Name\n\t}\n\n\treturn ids, names, nil\n}\n\nfunc GetAllSystemCount() (int64, error) {\n\tif !NewDbTransaction(DBConn).IsTable(ecosysTable) {\n\t\treturn 0, nil\n\t}\n\n\tvar total int64\n\tif err := DBConn.Model(Ecosystem{}).Count(&total).Error; err != nil {\n\t\treturn 0, err\n\t}\n\treturn total, nil\n}\n\n// GetEcoParam is ecosystem combustion percent, digits\nfunc GetEcoParam(db *DbTransaction, ids []int64) ([]EcoParam, error) {\n\tquery :=\n\t\t`\n\t\t\tSELECT eco.id,(eco.fee_mode_info::json#>>'{combustion,percent}')::int as percent ,eco.digits\n\t\t\tFROM \"1_parameters\" as par\n\t\t\tLEFT JOIN \"1_ecosystems\" as eco ON par.ecosystem = eco.id \n\t\t\tWHERE par.name = 'utxo_fee' and par.value = '1' and par.ecosystem IN ?\n\t\t`\n\n\tvar ret []EcoParam\n\tif len(ids) > 0 {\n\t\terr := GetDB(db).Raw(query, ids).Scan(&ret).Error\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\n// Get is fill receiver from db\nfunc (sys *Ecosystem) Get(dbTx *DbTransaction, id int64) (bool, error) {\n\treturn isFound(GetDB(dbTx).First(sys, \"id = ?\", id))\n}\n\n// Delete is deleting record\nfunc (sys *Ecosystem) Delete(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Delete(sys).Error\n}\n\n// FeeMode is get ecosystem fee mode\nfunc (sys *Ecosystem) FeeMode() (*FeeModeInfo, error) {\n\tif len(sys.TokenSymbol) == 0 || len(sys.FeeModeInfo) == 0 || sys.ID == consts.DefaultTokenEcosystem {\n\t\treturn nil, nil\n\t}\n\tvar info = &FeeModeInfo{}\n\terr := json.Unmarshal([]byte(sys.FeeModeInfo), info)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"Unmarshal eco[%d] feemode err\", sys.ID)\n\t}\n\treturn info, nil\n}\n\n// GetTokenSymbol is get ecosystem token symbol\nfunc (sys *Ecosystem) GetTokenSymbol(dbTx *DbTransaction, id int64) (bool, error) {\n\treturn isFound(GetDB(dbTx).Select(\"token_symbol\").First(sys, \"id = ?\", id))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/ecosystem_parameter.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nvar (\n\tEcosystemWallet = \"ecosystem_wallet\"\n)\n\n// StateParameter is model\ntype StateParameter struct {\n\tecosystem  int64\n\tID         int64  `gorm:\"primary_key;not null\"`\n\tName       string `gorm:\"not null;size:100\"`\n\tValue      string `gorm:\"not null\"`\n\tConditions string `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (sp *StateParameter) TableName() string {\n\tif sp.ecosystem == 0 {\n\t\tsp.ecosystem = 1\n\t}\n\treturn `1_parameters`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (sp *StateParameter) SetTablePrefix(prefix string) *StateParameter {\n\tsp.ecosystem = converter.StrToInt64(prefix)\n\treturn sp\n}\n\n// Get is retrieving model from database\nfunc (sp *StateParameter) Get(dbTx *DbTransaction, name string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"ecosystem = ? and name = ?\", sp.ecosystem, name).First(sp))\n}\n\n// GetAllStateParameters is returning all state parameters\nfunc (sp *StateParameter) GetAllStateParameters(offset, limit *int, names []string) ([]StateParameter, error) {\n\tparameters := make([]StateParameter, 0)\n\tq := DBConn.Table(sp.TableName()).Where(`ecosystem = ?`, sp.ecosystem)\n\n\tif len(names) > 0 {\n\t\t//if any select names,then all return\n\t\tq.Where(\"name IN ?\", names)\n\t} else {\n\t\tif offset != nil {\n\t\t\tq = q.Offset(*offset)\n\t\t}\n\t\tif limit != nil {\n\t\t\tq = q.Limit(*limit)\n\t\t}\n\t}\n\n\terr := q.Find(&parameters).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn parameters, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/external_blockchain.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// ExternalBlockchain represents a txinfo table\ntype ExternalBlockchain struct {\n\tId               int64  `gorm:\"primary_key;not null\"`\n\tValue            string `gorm:\"not null\"`\n\tExternalContract string `gorm:\"not null\"`\n\tResultContract   string `gorm:\"not null\"`\n\tUrl              string `gorm:\"not null\"`\n\tUid              string `gorm:\"not null\"`\n\tTxTime           int64  `gorm:\"not null\"`\n\tSent             int64  `gorm:\"not null\"`\n\tHash             []byte `gorm:\"not null\"`\n\tAttempts         int64  `gorm:\"not null\"`\n}\n\n// GetExternalList returns the list of network tx\nfunc GetExternalList() (list []ExternalBlockchain, err error) {\n\terr = DBConn.Table(\"external_blockchain\").\n\t\tOrder(\"id desc\").Scan(&list).Error\n\treturn\n}\n\n// DelExternalList deletes sent tx\nfunc DelExternalList(list []int64) error {\n\tslist := make([]string, len(list))\n\tfor i, v := range list {\n\t\tslist[i] = converter.Int64ToStr(v)\n\t}\n\treturn DBConn.Exec(\"delete from external_blockchain where id in (\" +\n\t\tstrings.Join(slist, `,`) + \")\").Error\n}\n\nfunc HashExternalTx(id int64, hash []byte) error {\n\treturn DBConn.Exec(\"update external_blockchain set hash=?, sent = 1 where id = ?\", hash, id).Error\n}\n\nfunc IncExternalAttempt(id int64) error {\n\treturn DBConn.Exec(\"update external_blockchain set attempts=attempts+1 where id = ?\", id).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/history.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"gorm.io/gorm\"\n\n\t\"github.com/shopspring/decimal\"\n)\n\n// History represent record of history table\ntype History struct {\n\tecosystem        int64\n\tID               int64\n\tSenderID         int64\n\tRecipientID      int64\n\tSenderBalance    decimal.Decimal\n\tRecipientBalance decimal.Decimal\n\tAmount           decimal.Decimal\n\tComment          string `json:\"comment,omitempty\"`\n\tBlockID          int64  `json:\"block_id,omitempty\"`\n\tTxHash           []byte `gorm:\"column:txhash\"`\n\tCreatedAt        int64  `json:\"created_at,omitempty\"`\n\tType             int64\n}\n\n// SetTablePrefix is setting table prefix\nfunc (h *History) SetTablePrefix(prefix int64) *History {\n\th.ecosystem = prefix\n\treturn h\n}\n\n// TableName returns table name\nfunc (h *History) TableName() string {\n\tif h.ecosystem == 0 {\n\t\th.ecosystem = 1\n\t}\n\treturn `1_history`\n}\n\n// MoneyTransfer from to amount\ntype MoneyTransfer struct {\n\tSenderID    int64\n\tRecipientID int64\n\tAmount      decimal.Decimal\n}\n\n// SenderTxCount struct to scan query result\ntype SenderTxCount struct {\n\tSenderID int64\n\tTxCount  int64\n}\n\n// Get is retrieving model from database\nfunc (ts *History) Get(transactionHash []byte) (bool, error) {\n\treturn isFound(DBConn.Table(ts.TableName()).Where(\"txhash = ?\", transactionHash).First(ts))\n}\n\n// GetExcessCommonTokenMovementPerDay returns sum of amounts 24 hours\nfunc GetExcessCommonTokenMovementPerDay(tx *DbTransaction) (amount decimal.Decimal, err error) {\n\tdb := GetDB(tx)\n\ttype result struct {\n\t\tAmount decimal.Decimal\n\t}\n\n\tvar res result\n\terr = db.Table(\"1_history\").Select(\"SUM(amount) as amount\").\n\t\tWhere(\"to_timestamp(created_at) > NOW() - interval '24 hours' AND amount > 0\").Scan(&res).Error\n\n\treturn res.Amount, err\n}\n\n// GetExcessFromToTokenMovementPerDay returns from to pairs where sum of amount greather than fromToPerDayLimit per 24 hours\nfunc GetExcessFromToTokenMovementPerDay(tx *DbTransaction) (excess []MoneyTransfer, err error) {\n\tdb := GetDB(tx)\n\terr = db.Table(\"1_history\").\n\t\tSelect(\"sender_id, recipient_id, SUM(amount) amount\").\n\t\tWhere(\"to_timestamp(created_at) > NOW() - interval '24 hours' AND amount > 0\").\n\t\tGroup(\"sender_id, recipient_id\").\n\t\tHaving(\"SUM(amount) > ?\", consts.FromToPerDayLimit).\n\t\tScan(&excess).Error\n\n\treturn excess, err\n}\n\n// GetExcessTokenMovementQtyPerBlock returns from to pairs where money transactions count greather than tokenMovementQtyPerBlockLimit per 24 hours\nfunc GetExcessTokenMovementQtyPerBlock(tx *DbTransaction, blockID int64) (excess []SenderTxCount, err error) {\n\tdb := GetDB(tx)\n\terr = db.Table(\"1_history\").\n\t\tSelect(\"sender_id, count(*) tx_count\").\n\t\tWhere(\"block_id = ? AND amount > ?\", blockID, 0).\n\t\tGroup(\"sender_id\").\n\t\tHaving(\"count(*) > ?\", consts.TokenMovementQtyPerBlockLimit).\n\t\tScan(&excess).Error\n\n\treturn excess, err\n}\n\nfunc GetWalletRecordHistory(tx *DbTransaction, keyId string, searchType string, limit, offset int) (histories []History, total int64, err error) {\n\tdb := GetDB(tx)\n\tvar query *gorm.DB\n\tif searchType == \"income\" {\n\t\tquery = db.Table(\"1_history\").\n\t\t\tWhere(\"recipient_id = ?\", keyId)\n\t} else if searchType == \"outcome\" {\n\t\tquery = db.Table(\"1_history\").\n\t\t\tWhere(\"sender_id = ?\", keyId)\n\t} else {\n\t\tquery = db.Table(\"1_history\").\n\t\t\tWhere(\"recipient_id = ? OR sender_id = ?\", keyId, keyId)\n\t}\n\terr = query.Count(&total).Error\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\terr = query.\n\t\tOrder(\"id desc\").\n\t\tLimit(limit).\n\t\tOffset(offset).Scan(&histories).Error\n\treturn\n}\n"
  },
  {
    "path": "packages/storage/sqldb/info_block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// InfoBlock is model\ntype InfoBlock struct {\n\tHash           []byte `gorm:\"not null\"`\n\tEcosystemID    int64  `gorm:\"not null default 0\"`\n\tKeyID          int64  `gorm:\"not null default 0\"`\n\tNodePosition   string `gorm:\"not null default 0\"`\n\tBlockID        int64  `gorm:\"not null\"`\n\tTime           int64  `gorm:\"not null\"`\n\tCurrentVersion string `gorm:\"not null\"`\n\tSent           int8   `gorm:\"not null\"`\n\tRollbacksHash  []byte `gorm:\"not null\"`\n\tConsensusMode  int32  `gorm:\"not null\"`\n\tCandidateNodes []byte `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (ib *InfoBlock) TableName() string {\n\treturn \"info_block\"\n}\n\n// Get is retrieving model from database\nfunc (ib *InfoBlock) Get() (bool, error) {\n\treturn isFound(DBConn.Last(ib))\n}\n\n// Update is update model\nfunc (ib *InfoBlock) Update(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Model(&InfoBlock{}).Updates(ib).Error\n}\n\n// GetUnsent is retrieving model from database\nfunc (ib *InfoBlock) GetUnsent() (bool, error) {\n\treturn isFound(DBConn.Where(\"sent = ?\", \"0\").First(&ib))\n}\n\n// Create is creating record of model\nfunc (ib *InfoBlock) Create(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Create(ib).Error\n}\n\n// MarkSent update model sent field\nfunc (ib *InfoBlock) MarkSent() error {\n\treturn DBConn.Model(ib).Update(\"sent\", 1).Error\n}\n\n// UpdRollbackHash update model rollbacks_hash field\nfunc UpdRollbackHash(dbTx *DbTransaction, hash []byte) error {\n\treturn GetDB(dbTx).Model(&InfoBlock{}).Update(\"rollbacks_hash\", hash).Error\n}\n\n// BlockGetUnsent returns InfoBlock\nfunc BlockGetUnsent() (*InfoBlock, error) {\n\tib := &InfoBlock{}\n\tfound, err := ib.GetUnsent()\n\tif !found {\n\t\treturn nil, err\n\t}\n\treturn ib, err\n}\n\n// Marshall returns block as []byte\nfunc (ib *InfoBlock) Marshall() []byte {\n\tif ib != nil {\n\t\ttoBeSent := converter.DecToBin(ib.BlockID, 3)\n\t\treturn append(toBeSent, ib.Hash...)\n\t}\n\treturn []byte{}\n}\n"
  },
  {
    "path": "packages/storage/sqldb/install.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\n// ProgressComplete status of installation progress\nconst ProgressComplete = \"complete\"\n\n// Install is model\ntype Install struct {\n\tProgress string `gorm:\"not null;size:10\"`\n}\n\n// TableName returns name of table\nfunc (i *Install) TableName() string {\n\treturn \"install\"\n}\n\n// Get is retrieving model from database\nfunc (i *Install) Get() error {\n\treturn DBConn.Find(i).Error\n}\n\n// Create is creating record of model\nfunc (i *Install) Create() error {\n\treturn DBConn.Create(i).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/keys.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/shopspring/decimal\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// Key is model\ntype Key struct {\n\tecosystem    int64\n\taccountKeyID int64 `gorm:\"-\"`\n\n\tID        int64  `gorm:\"primary_key;not null\"`\n\tAccountID string `gorm:\"column:account;not null\"`\n\tPublicKey []byte `gorm:\"column:pub;not null\"`\n\tAmount    string `gorm:\"not null\"`\n\tMaxpay    string `gorm:\"not null\"`\n\tDeleted   int64  `gorm:\"not null\"`\n\tBlocked   int64  `gorm:\"not null\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (m *Key) SetTablePrefix(prefix int64) *Key {\n\tm.ecosystem = prefix\n\treturn m\n}\n\n// TableName returns name of table\nfunc (m Key) TableName() string {\n\tif m.ecosystem == 0 {\n\t\tm.ecosystem = 1\n\t}\n\treturn `1_keys`\n}\nfunc (m *Key) Disable() bool {\n\treturn m.Deleted != 0 || m.Blocked != 0\n}\nfunc (m *Key) CapableAmount() decimal.Decimal {\n\tamount := decimal.Zero\n\tif len(m.Amount) > 0 {\n\t\tamount, _ = decimal.NewFromString(m.Amount)\n\t}\n\tmaxpay := decimal.Zero\n\tif len(m.Maxpay) > 0 {\n\t\tmaxpay, _ = decimal.NewFromString(m.Maxpay)\n\t}\n\tif maxpay.GreaterThan(decimal.Zero) && maxpay.LessThan(amount) {\n\t\tamount = maxpay\n\t}\n\treturn amount\n}\n\n// Get is retrieving model from database\nfunc (m *Key) Get(db *DbTransaction, wallet int64) (bool, error) {\n\treturn isFound(GetDB(db).Where(\"id = ? and ecosystem = ?\", wallet, m.ecosystem).First(m))\n}\n\nfunc (m *Key) AccountKeyID() int64 {\n\tif m.accountKeyID == 0 {\n\t\tm.accountKeyID = converter.StringToAddress(m.AccountID)\n\t}\n\treturn m.accountKeyID\n}\n\n// KeyTableName returns name of key table\nfunc KeyTableName(prefix int64) string {\n\treturn fmt.Sprintf(\"%d_keys\", prefix)\n}\n\n// GetKeysCount returns common count of keys\nfunc GetKeysCount() (int64, error) {\n\tvar cnt int64\n\trow := DBConn.Raw(`SELECT count(*) key_count FROM \"1_keys\" WHERE ecosystem = 1`).Select(\"key_count\").Row()\n\terr := row.Scan(&cnt)\n\treturn cnt, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/language.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// Language is model\ntype Language struct {\n\tecosystem  int64\n\tID         int64  `gorm:\"primary_key;not null\"`\n\tName       string `gorm:\"not null;size:100\"`\n\tRes        string `gorm:\"type:jsonb\"`\n\tConditions string `gorm:\"not null\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (l *Language) SetTablePrefix(prefix string) {\n\tl.ecosystem = converter.StrToInt64(prefix)\n}\n\n// TableName returns name of table\nfunc (l *Language) TableName() string {\n\tif l.ecosystem == 0 {\n\t\tl.ecosystem = 1\n\t}\n\treturn `1_languages`\n}\n\n// GetAll is retrieving all records from database\nfunc (l *Language) GetAll(dbTx *DbTransaction, prefix string) ([]Language, error) {\n\tresult := new([]Language)\n\terr := GetDB(dbTx).Table(\"1_languages\").Where(\"ecosystem = ?\", prefix).Order(\"name asc\").Find(&result).Error\n\treturn *result, err\n}\n\n// ToMap is converting model to map\nfunc (l *Language) ToMap() map[string]string {\n\tresult := make(map[string]string, 0)\n\tresult[\"name\"] = l.Name\n\tresult[\"res\"] = l.Res\n\tresult[\"conditions\"] = l.Conditions\n\treturn result\n}\n"
  },
  {
    "path": "packages/storage/sqldb/log_transaction.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"gorm.io/gorm\"\n)\n\n// LogTransaction is model\ntype LogTransaction struct {\n\tHash  []byte `gorm:\"primary_key;not null\"`\n\tBlock int64  `gorm:\"not null\"`\n\t//TxData       []byte `gorm:\"not null\"`\n\tTimestamp    int64  `gorm:\"not null\"`\n\tAddress      int64  `gorm:\"not null\"`\n\tEcosystemID  int64  `gorm:\"not null\"`\n\tStatus       int64  `gorm:\"not null\"`\n\tContractName string `gorm:\"not null\"`\n}\n\n// GetByHash returns LogTransactions existence by hash\nfunc (lt *LogTransaction) GetByHash(dbTx *DbTransaction, hash []byte) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"hash = ?\", hash).First(lt))\n}\n\n// Create is creating record of model\nfunc (lt *LogTransaction) Create(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Create(lt).Error\n}\n\nfunc CreateLogTransactionBatches(dbTx *gorm.DB, lts []*LogTransaction) error {\n\tif len(lts) == 0 {\n\t\treturn nil\n\t}\n\treturn dbTx.Model(&LogTransaction{}).Create(&lts).Error\n}\n\n// DeleteLogTransactionsByHash is deleting record by hash\nfunc DeleteLogTransactionsByHash(dbTx *DbTransaction, hash []byte) (int64, error) {\n\tquery := GetDB(dbTx).Exec(\"DELETE FROM log_transactions WHERE hash = ?\", hash)\n\treturn query.RowsAffected, query.Error\n}\n\n// GetLogTransactionsCount count records by transaction hash\nfunc GetLogTransactionsCount(hash []byte) (int64, error) {\n\tvar rowsCount int64\n\tif err := DBConn.Table(\"log_transactions\").Where(\"hash = ?\", hash).Count(&rowsCount).Error; err != nil {\n\t\treturn -1, err\n\t}\n\treturn rowsCount, nil\n}\n\n// GetLogTxCount count records by ecosystemID\nfunc GetLogTxCount(dbTx *DbTransaction, ecosystemID int64) (int64, error) {\n\tvar rowsCount int64\n\tif err := GetDB(dbTx).Table(\"log_transactions\").Where(\"ecosystem_id = ? and status = 0\", ecosystemID).Count(&rowsCount).Error; err != nil {\n\t\treturn -1, err\n\t}\n\treturn rowsCount, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/members.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport \"github.com/IBAX-io/go-ibax/packages/converter\"\n\n// Member represents a ecosystem member\ntype Member struct {\n\tecosystem  int64\n\tID         int64  `gorm:\"primary_key;not null\"`\n\tMemberName string `gorm:\"not null\"`\n\tImageID    *int64\n\tMemberInfo string `gorm:\"type:jsonb\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (m *Member) SetTablePrefix(prefix string) {\n\tm.ecosystem = converter.StrToInt64(prefix)\n}\n\n// TableName returns name of table\nfunc (m *Member) TableName() string {\n\tif m.ecosystem == 0 {\n\t\tm.ecosystem = 1\n\t}\n\treturn `1_members`\n}\n\n// Count returns count of records in table\nfunc (m *Member) Count() (count int64, err error) {\n\terr = DBConn.Table(m.TableName()).Where(`ecosystem=?`, m.ecosystem).Count(&count).Error\n\treturn\n}\n\n// Get init m as member with ID\nfunc (m *Member) Get(account string) (bool, error) {\n\treturn isFound(DBConn.Where(\"ecosystem=? and account = ?\", m.ecosystem, account).First(m))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/menu.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport \"github.com/IBAX-io/go-ibax/packages/converter\"\n\n// Menu is model\ntype Menu struct {\n\tecosystem  int64\n\tID         int64  `gorm:\"primary_key;not null\" json:\"id\"`\n\tName       string `gorm:\"not null\" json:\"name\"`\n\tTitle      string `gorm:\"not null\" json:\"title\"`\n\tValue      string `gorm:\"not null\" json:\"value\"`\n\tConditions string `gorm:\"not null\" json:\"conditions\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (m *Menu) SetTablePrefix(prefix string) {\n\tm.ecosystem = converter.StrToInt64(prefix)\n}\n\n// TableName returns name of table\nfunc (m Menu) TableName() string {\n\tif m.ecosystem == 0 {\n\t\tm.ecosystem = 1\n\t}\n\treturn `1_menu`\n}\n\n// Get is retrieving model from database\nfunc (m *Menu) Get(name string) (bool, error) {\n\treturn isFound(DBConn.Where(\"ecosystem=? and name = ?\", m.ecosystem, name).First(m))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/metric.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\nconst tableNameMetrics = \"1_metrics\"\n\n// Metric represents record of system_metrics table\ntype Metric struct {\n\tID     int64  `gorm:\"primary_key;not null\"`\n\tTime   int64  `gorm:\"not null\"`\n\tMetric string `gorm:\"not null\"`\n\tKey    string `gorm:\"not null\"`\n\tValue  int64  `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (Metric) TableName() string {\n\treturn tableNameMetrics\n}\n\n// EcosystemTx represents value of metric\ntype EcosystemTx struct {\n\tUnixTime  int64\n\tEcosystem string\n\tCount     int64\n}\n\n// GetEcosystemTxPerDay returns the count of transactions per day for ecosystems,\n// processes data for two days\nfunc GetEcosystemTxPerDay(timeBlock int64) ([]*EcosystemTx, error) {\n\tcurDate := time.Unix(timeBlock, 0).Format(`2006-01-02`)\n\tsql := `SELECT\n\t\tEXTRACT(EPOCH FROM to_timestamp(bc.time)::date)::int \"unix_time\",\n\t\tSUBSTRING(rtx.table_name FROM '^\\d+') \"ecosystem\",\n\t\tCOUNT(*)\n\tFROM rollback_tx rtx\n\t\tINNER JOIN block_chain bc ON bc.id = rtx.block_id\n\tWHERE to_timestamp(bc.time)::date >= (DATE('` + curDate + `') - interval '1' day)::date\n\tGROUP BY unix_time, ecosystem ORDER BY unix_time, ecosystem`\n\n\tvar ecosystemTx []*EcosystemTx\n\terr := DBConn.Raw(sql).Scan(&ecosystemTx).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ecosystemTx, err\n}\n\n// GetMetricValues returns aggregated metric values in the time interval\nfunc GetMetricValues(metric, timeInterval, aggregateFunc, timeBlock string) ([]any, error) {\n\trows, err := DBConn.Table(tableNameMetrics).Select(\"key,\"+aggregateFunc+\"(value)\").\n\t\tWhere(\"metric = ? AND time >= EXTRACT(EPOCH FROM TIMESTAMP '\"+timeBlock+\"' - CAST(? AS INTERVAL))\",\n\t\t\tmetric, timeInterval).Order(\"id asc\").\n\t\tGroup(\"key, id\").Rows()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar (\n\t\tresult = []any{}\n\t\tkey    string\n\t\tvalue  string\n\t)\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tif err := rows.Scan(&key, &value); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult = append(result, types.LoadMap(map[string]any{\n\t\t\t\"key\":   key,\n\t\t\t\"value\": value,\n\t\t}))\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/migration_history.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"time\"\n)\n\nconst noVersion = \"0.0.0\"\n\n// MigrationHistory is model\ntype MigrationHistory struct {\n\tID          int64  `gorm:\"primary_key;not null\"`\n\tVersion     string `gorm:\"not null\"`\n\tDateApplied int64  `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (mh *MigrationHistory) TableName() string {\n\treturn \"migration_history\"\n}\n\n// CurrentVersion returns current version of database migrations\nfunc (mh *MigrationHistory) CurrentVersion() (string, error) {\n\tif !NewDbTransaction(DBConn).IsTable(mh.TableName()) {\n\t\treturn noVersion, nil\n\t}\n\n\terr := DBConn.Last(mh).Error\n\n\tif mh.Version == \"\" {\n\t\treturn noVersion, nil\n\t}\n\n\treturn mh.Version, err\n}\n\n// ApplyMigration executes database schema and writes migration history\nfunc (mh *MigrationHistory) ApplyMigration(version, query string) error {\n\terr := DBConn.Exec(query).Error\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn DBConn.Create(&MigrationHistory{Version: version, DateApplied: time.Now().Unix()}).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/node_ban_logs.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport \"time\"\n\ntype NodeBanLogs struct {\n\tID       int64\n\tBannedAt time.Time\n\tBanTime  time.Duration\n\tReason   string\n}\n\n// TableName returns name of table\nfunc (r NodeBanLogs) TableName() string {\n\treturn \"1_node_ban_logs\"\n}\n"
  },
  {
    "path": "packages/storage/sqldb/notification.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nconst (\n\tnotificationTableSuffix = \"_notifications\"\n\n\tNotificationTypeSingle = 1\n\tNotificationTypeRole   = 2\n)\n\n// Notification structure\ntype Notification struct {\n\tecosystem           int64\n\tID                  int64  `gorm:\"primary_key;not null\"`\n\tRecipient           string `gorm:\"type:jsonb\"`\n\tSender              string `gorm:\"type:jsonb\"`\n\tNotification        string `gorm:\"type:jsonb\"`\n\tPageParams          string `gorm:\"type:jsonb\"`\n\tProcessingInfo      string `gorm:\"type:jsonb\"`\n\tPageName            string `gorm:\"size:255\"`\n\tDateCreated         int64\n\tDateStartProcessing int64\n\tDateClosed          int64\n\tClosed              bool\n}\n\n// SetTablePrefix set table Prefix\nfunc (n *Notification) SetTablePrefix(tablePrefix string) {\n\tn.ecosystem = converter.StrToInt64(tablePrefix)\n}\n\n// TableName returns table name\nfunc (n *Notification) TableName() string {\n\tif n.ecosystem == 0 {\n\t\tn.ecosystem = 1\n\t}\n\treturn `1_notifications`\n}\n\ntype NotificationsCount struct {\n\tRecipientID int64  `gorm:\"recipient_id\"`\n\tAccount     string `gorm:\"account\"`\n\tRoleID      int64  `gorm:\"role_id\"`\n\tCount       int64  `gorm:\"count\"`\n}\n\n// GetNotificationsCount returns all unclosed notifications by users and ecosystem through role_id\n// if userIDs is nil or empty then filter will be skipped\nfunc GetNotificationsCount(ecosystemID int64, accounts []string) ([]NotificationsCount, error) {\n\tresult := make([]NotificationsCount, 0, len(accounts))\n\tfor _, account := range accounts {\n\t\tquery := `SELECT k.id as \"recipient_id\", '0' as \"role_id\", count(n.id), k.account\n\t\t\tFROM \"1_keys\" k\n\t\t\tLEFT JOIN \"1_notifications\" n ON n.ecosystem = k.ecosystem AND n.closed = 0 AND n.notification->>'type' = '1' and n.recipient->>'account' = k.account\n\t\t\tWHERE k.ecosystem = ? AND k.account = ?\n\t\t\tGROUP BY recipient_id, k.account, role_id\n\t\t\tUNION\n\t\t\tSELECT k.id as \"recipient_id\", rp.role->>'id' as \"role_id\", count(n.id), k.account\n\t\t\tFROM \"1_keys\" k\n\t\t\tINNER JOIN \"1_roles_participants\" rp ON rp.member->>'account' = k.account\n\t\t\tLEFT JOIN \"1_notifications\" n ON n.ecosystem = k.ecosystem AND n.closed = 0 AND n.notification->>'type' = '2' AND n.recipient->>'role_id' = rp.role->>'id'\n\t\t\t\t\t\t\t\t\t\t\t\t\tAND (n.date_start_processing = 0 OR n.processing_info->>'account' = k.account)\n\t\t\tWHERE k.ecosystem=? AND k.account = ?\n\t\t\tGROUP BY recipient_id, k.account, role_id`\n\n\t\tlist := make([]NotificationsCount, 0)\n\t\terr := GetDB(nil).Raw(query, ecosystemID, account, ecosystemID, account).Scan(&list).Error\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult = append(result, list...)\n\t}\n\treturn result, nil\n}\n\nfunc getNotificationCountFilter(users []int64, ecosystemID int64) (filter string, params []any) {\n\tfilter = fmt.Sprintf(` WHERE closed = 0 and ecosystem = '%d' `, ecosystemID)\n\n\tif len(users) > 0 {\n\t\tfilter += `AND recipient->>'member_id' IN (?) `\n\t\tusersStrs := []string{}\n\t\tfor _, user := range users {\n\t\t\tusersStrs = append(usersStrs, converter.Int64ToStr(user))\n\t\t}\n\t\tparams = append(params, usersStrs)\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "packages/storage/sqldb/notification_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype testItem struct {\n\tInput        []int64\n\tFilter       string\n\tParamsLength int\n}\n\nfunc TestGetNotificationCountFilter(t *testing.T) {\n\ttestTable := []testItem{\n\t\t{\n\t\t\tInput:        []int64{3, 5},\n\t\t\tFilter:       ` WHERE closed = false AND recipient_id IN (?) `,\n\t\t\tParamsLength: 1,\n\t\t},\n\t\t{\n\t\t\tInput:        nil,\n\t\t\tFilter:       ` WHERE closed = false `,\n\t\t\tParamsLength: 0,\n\t\t},\n\t}\n\n\tfor i, item := range testTable {\n\t\tfilter, params := getNotificationCountFilter(item.Input, 1)\n\t\tassert.Equal(t, item.Filter, filter, \"on %d step wrong filter %s\", i, filter)\n\t\tassert.Equal(t, item.ParamsLength, len(params), \"on %d step wrong params length %d\", i, len(params))\n\t}\n\n}\n"
  },
  {
    "path": "packages/storage/sqldb/ordering.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\ntype ordering string\n\nconst (\n\t// OrderASC as ASC\n\tOrderASC = ordering(\"ASC\")\n\t// OrderDESC as DESC\n\tOrderDESC = ordering(\"DESC\")\n)\n"
  },
  {
    "path": "packages/storage/sqldb/pages.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport \"github.com/IBAX-io/go-ibax/packages/converter\"\n\n// Page is model\ntype Page struct {\n\tecosystem     int64\n\tID            int64  `gorm:\"primary_key;not null\" json:\"id,omitempty\"`\n\tName          string `gorm:\"not null\" json:\"name,omitempty\"`\n\tValue         string `gorm:\"not null\" json:\"value,omitempty\"`\n\tMenu          string `gorm:\"not null;size:255\" json:\"menu,omitempty\"`\n\tValidateCount int64  `gorm:\"not null\" json:\"nodesCount,omitempty\"`\n\tAppID         int64  `gorm:\"column:app_id;not null\" json:\"app_id,omitempty\"`\n\tConditions    string `gorm:\"not null\" json:\"conditions,omitempty\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (p *Page) SetTablePrefix(prefix string) {\n\tp.ecosystem = converter.StrToInt64(prefix)\n}\n\n// TableName returns name of table\nfunc (p *Page) TableName() string {\n\tif p.ecosystem == 0 {\n\t\tp.ecosystem = 1\n\t}\n\treturn `1_pages`\n}\n\n// Get is retrieving model from database\nfunc (p *Page) Get(name string) (bool, error) {\n\treturn isFound(DBConn.Where(\"ecosystem=? and name = ?\", p.ecosystem, name).First(p))\n}\n\n// Count returns count of records in table\nfunc (p *Page) Count() (count int64, err error) {\n\terr = DBConn.Table(p.TableName()).Count(&count).Error\n\treturn\n}\n\n// GetByApp returns all pages belonging to selected app\nfunc (p *Page) GetByApp(appID int64, ecosystemID int64) ([]Page, error) {\n\tvar result []Page\n\terr := DBConn.Select(\"id, name\").Where(\"app_id = ? and ecosystem = ?\", appID, ecosystemID).Find(&result).Error\n\treturn result, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/platform_parameter.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage sqldb\n\nimport (\n\t\"encoding/json\"\n)\n\n// PlatformParameter is model\ntype PlatformParameter struct {\n\tID         int64  `gorm:\"primary_key;not null;\"`\n\tName       string `gorm:\"not null;size:255\"`\n\tValue      string `gorm:\"not null\"`\n\tConditions string `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (sp PlatformParameter) TableName() string {\n\treturn \"1_platform_parameters\"\n}\n\n// Get is retrieving model from database\nfunc (sp *PlatformParameter) Get(dbTx *DbTransaction, name string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"name = ?\", name).First(sp))\n}\n\n// GetTransaction is retrieving model from database using transaction\nfunc (sp *PlatformParameter) GetTransaction(dbTx *DbTransaction, name string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"name = ?\", name).First(sp))\n}\n\n// GetJSONField returns fields as json\nfunc (sp *PlatformParameter) GetJSONField(jsonField string, name string) (string, error) {\n\tvar result string\n\terr := DBConn.Table(\"1_platform_parameters\").Where(\"name = ?\", name).Select(jsonField).Row().Scan(&result)\n\treturn result, err\n}\n\n// GetValueParameterByName returns value parameter by name\nfunc (sp *PlatformParameter) GetValueParameterByName(name, value string) (*string, error) {\n\tvar result *string\n\terr := DBConn.Raw(`SELECT value->'`+value+`' FROM \"1_platform_parameters\" WHERE name = ?`, name).Row().Scan(&result)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\n// GetAllPlatformParameters returns all platform parameters\nfunc GetAllPlatformParameters(dbTx *DbTransaction, offset, limit *int, names []string) ([]PlatformParameter, error) {\n\tparameters := new([]PlatformParameter)\n\tq := GetDB(dbTx)\n\tif len(names) > 0 {\n\t\t//if any select names,then all return\n\t\tq = q.Where(\"name IN ?\", names)\n\t} else {\n\t\tif offset != nil {\n\t\t\tq = q.Offset(*offset)\n\t\t}\n\t\tif limit != nil {\n\t\t\tq = q.Limit(*limit)\n\t\t}\n\t}\n\tif err := q.Find(&parameters).Error; err != nil {\n\t\treturn nil, err\n\t}\n\treturn *parameters, nil\n}\n\n// ToMap is converting PlatformParameter to map\nfunc (sp *PlatformParameter) ToMap() map[string]string {\n\tresult := make(map[string]string, 0)\n\tresult[\"name\"] = sp.Name\n\tresult[\"value\"] = sp.Value\n\tresult[\"conditions\"] = sp.Conditions\n\treturn result\n}\n\n// Update is update model\nfunc (sp PlatformParameter) Update(dbTx *DbTransaction, value string) error {\n\treturn GetDB(dbTx).Model(sp).Where(\"name = ?\", sp.Name).Update(`value`, value).Error\n}\n\n// SaveArray is saving array\nfunc (sp *PlatformParameter) SaveArray(dbTx *DbTransaction, list [][]string) error {\n\tret, err := json.Marshal(list)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn sp.Update(dbTx, string(ret))\n}\n\nfunc (sp *PlatformParameter) GetNumberOfHonorNodes() (int, error) {\n\tvar hns []map[string]any\n\tf, err := sp.GetTransaction(nil, `honor_nodes`)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif f {\n\t\tif len(sp.Value) > 0 {\n\t\t\tif err := json.Unmarshal([]byte(sp.Value), &hns); err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(hns) == 0 || len(hns) == 1 {\n\t\treturn 0, nil\n\t}\n\treturn len(hns), nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/queryBuilder/expression.go",
    "content": "package queryBuilder\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\nfunc GetOrder(tblname string, inOrder any, withDefault bool) (string, error) {\n\tvar (\n\t\torders           []string\n\t\tdefaultSortOrder = map[string]string{\n\t\t\t`keys`:    \"ecosystem,id\",\n\t\t\t`members`: \"ecosystem,id\",\n\t\t}\n\t)\n\tcols := types.NewMap()\n\n\tsanitize := func(in string, value any) {\n\t\tin = converter.Sanitize(strings.ToLower(in), ``)\n\t\tif len(in) > 0 {\n\t\t\tcols.Set(in, true)\n\t\t\tin = `\"` + in + `\"`\n\t\t\tif fmt.Sprint(value) == `-1` {\n\t\t\t\tin += ` desc`\n\t\t\t} else if fmt.Sprint(value) == `1` {\n\t\t\t\tin += ` asc`\n\t\t\t} else {\n\t\t\t\tin += ` asc`\n\t\t\t}\n\t\t\torders = append(orders, in)\n\t\t} else {\n\t\t\torders = append(orders, `\"id\" asc`)\n\t\t}\n\t}\n\tif withDefault {\n\t\tif v, ok := defaultSortOrder[tblname[2:]]; ok {\n\t\t\tfor _, item := range strings.Split(v, `,`) {\n\t\t\t\tcols.Set(item, false)\n\t\t\t}\n\t\t} else {\n\t\t\tcols.Set(`id`, false)\n\t\t}\n\t}\n\tswitch v := inOrder.(type) {\n\tcase string:\n\t\tsanitize(v, nil)\n\tcase *types.Map:\n\t\tfor _, ikey := range v.Keys() {\n\t\t\titem, _ := v.Get(ikey)\n\t\t\tsanitize(ikey, item)\n\t\t}\n\tcase map[string]any:\n\t\tfor ikey, item := range v {\n\t\t\tsanitize(ikey, item)\n\t\t}\n\tcase []any:\n\t\tfor _, item := range v {\n\t\t\tswitch param := item.(type) {\n\t\t\tcase string:\n\t\t\t\tsanitize(param, nil)\n\t\t\tcase *types.Map:\n\t\t\t\tfor _, ikey := range param.Keys() {\n\t\t\t\t\titem, _ := param.Get(ikey)\n\t\t\t\t\tsanitize(ikey, item)\n\t\t\t\t}\n\t\t\tcase map[string]any:\n\t\t\t\tfor key, value := range param {\n\t\t\t\t\tsanitize(key, value)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor _, key := range cols.Keys() {\n\t\tif state, found := cols.Get(key); !found || !state.(bool) {\n\t\t\torders = append(orders, key)\n\t\t}\n\t}\n\tif err := CheckNow(orders...); err != nil {\n\t\treturn ``, err\n\t}\n\treturn strings.Join(orders, `,`), nil\n}\n\nfunc GetColumns(inColumns any) ([]string, error) {\n\tvar columns []string\n\n\tswitch v := inColumns.(type) {\n\tcase string:\n\t\tif len(v) > 0 {\n\t\t\tcolumns = strings.Split(v, `,`)\n\t\t}\n\tcase []any:\n\t\tfor _, name := range v {\n\t\t\tswitch col := name.(type) {\n\t\t\tcase string:\n\t\t\t\tcolumns = append(columns, col)\n\t\t\t}\n\t\t}\n\t}\n\tif len(columns) == 0 {\n\t\tcolumns = []string{`*`}\n\t}\n\tfor i, v := range columns {\n\t\tcolumns[i] = converter.Sanitize(strings.ToLower(v), `*->`)\n\t}\n\tif err := CheckNow(columns...); err != nil {\n\t\treturn nil, err\n\t}\n\treturn columns, nil\n}\n\nfunc GetTableName(ecosystem int64, tblname string) string {\n\treturn converter.ParseTable(tblname, ecosystem)\n}\n"
  },
  {
    "path": "packages/storage/sqldb/queryBuilder/query_builder.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage queryBuilder\n\nimport (\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tprefTimestamp      = \"timestamp\"\n\tprefTimestampSpace = \"timestamp \"\n)\n\nvar (\n\tcheckNowRE = regexp.MustCompile(`(now\\s*\\(\\s*\\)|localtime|current_date|current_time|current_timestamp)`)\n\tErrNow     = errors.New(`it is prohibited to use current_time or current_date or localtime or current_timestamp sql keyword`)\n)\n\n// KeyTableChecker checks table\ntype KeyTableChecker interface {\n\tIsKeyTable(string) bool\n}\n\ntype NextIDGetter interface {\n\tGetNextID(string) (int64, error)\n}\n\ntype SQLQueryBuilder struct {\n\t*log.Entry\n\ttableID      string\n\tTable        string\n\tisKeyTable   bool\n\tprepared     bool\n\tkeyEcosystem string\n\tkeyName      string\n\tFields       []string\n\tFieldValues  []any\n\tstringValues []string\n\tWhere        *types.Map\n\tKeyTableChkr KeyTableChecker\n\twhereExpr    string\n\tTxEcoID      int64\n}\n\nfunc (b *SQLQueryBuilder) Prepare() error {\n\tif b.prepared {\n\t\treturn nil\n\t}\n\n\tidNames := strings.SplitN(b.Table, `_`, 2)\n\tif len(idNames) == 2 {\n\t\tb.keyName = idNames[1]\n\n\t\tif b.KeyTableChkr.IsKeyTable(b.keyName) {\n\t\t\tb.isKeyTable = true\n\t\t\tif b.TxEcoID > 1 {\n\t\t\t\tif b.Table == \"1_keys\" {\n\t\t\t\t\tb.keyEcosystem = idNames[0]\n\t\t\t\t} else {\n\t\t\t\t\tb.keyEcosystem = converter.Int64ToStr(b.TxEcoID)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tb.keyEcosystem = idNames[0]\n\t\t\t}\n\t\t\tb.Table = `1_` + b.keyName\n\n\t\t\tif contains, ecosysIndx := isParamsContainsEcosystem(b.Fields, b.FieldValues); contains {\n\t\t\t\tif b.Where.IsEmpty() {\n\t\t\t\t\tb.keyEcosystem = fmt.Sprint(b.FieldValues[ecosysIndx])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tb.Fields = append(b.Fields, \"ecosystem\")\n\t\t\t\tb.FieldValues = append(b.FieldValues, b.keyEcosystem)\n\t\t\t}\n\t\t}\n\t}\n\n\tif err := b.normalizeValues(); err != nil {\n\t\tb.WithError(err).Error(\"on normalize field values\")\n\t\treturn err\n\t}\n\n\tvalues, err := converter.InterfaceSliceToStr(b.FieldValues)\n\tif err != nil {\n\t\tb.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"on convert field values to string\")\n\t\treturn err\n\t}\n\n\tb.stringValues = values\n\tb.prepared = true\n\treturn nil\n}\n\nfunc (b *SQLQueryBuilder) SetTableID(id string) {\n\tb.tableID = id\n}\n\nfunc (b *SQLQueryBuilder) TableID() string {\n\treturn b.tableID\n}\n\nfunc (b *SQLQueryBuilder) GetSelectExpr() (string, error) {\n\tif err := b.Prepare(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfieldsExpr, err := b.GetSQLSelectFieldsExpr()\n\tif err != nil {\n\t\tb.WithError(err).Error(\"on getting sql fields statement\")\n\t\treturn \"\", err\n\t}\n\n\twhereExpr, err := b.GetSQLWhereExpr()\n\tif err != nil {\n\t\tb.WithError(err).Error(\"on getting sql where statement\")\n\t\treturn \"\", err\n\t}\n\treturn fmt.Sprintf(`SELECT %s FROM \"%s\" %s`, fieldsExpr, b.Table, whereExpr), nil\n}\n\nfunc (b *SQLQueryBuilder) GetSQLSelectFieldsExpr() (string, error) {\n\tif err := b.Prepare(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tsqlFields := make([]string, 0, len(b.Fields)+1)\n\tsqlFields = append(sqlFields, \"id\")\n\n\tfor i := range b.Fields {\n\t\tb.Fields[i] = strings.TrimSpace(strings.ToLower(b.Fields[i]))\n\t\tsqlFields = append(sqlFields, toSQLField(b.Fields[i]))\n\t}\n\n\treturn strings.Join(sqlFields, \",\"), nil\n}\n\nfunc (b *SQLQueryBuilder) GetSQLWhereExpr() (string, error) {\n\tvar err error\n\n\tif err = b.Prepare(); err != nil {\n\t\treturn \"\", err\n\t}\n\tif b.Where.IsEmpty() {\n\t\treturn \"\", nil\n\t}\n\tif b.whereExpr != \"\" {\n\t\treturn b.whereExpr, nil\n\t}\n\tif b.isKeyTable {\n\t\tif _, isEcosystem := b.Where.Get(`ecosystem`); !isEcosystem {\n\t\t\tb.Where.Set(`ecosystem`, converter.StrToInt64(b.keyEcosystem))\n\t\t}\n\t}\n\tb.whereExpr, err = GetWhere(b.Where)\n\tif err != nil {\n\t\treturn ``, err\n\t}\n\tif len(b.whereExpr) > 0 {\n\t\tb.whereExpr = \" WHERE \" + b.whereExpr\n\t\treturn b.whereExpr, nil\n\t}\n\treturn \"\", nil\n}\n\nfunc (b *SQLQueryBuilder) GetSQLUpdateExpr(logData map[string]string) (string, error) {\n\tif err := b.Prepare(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\texpressions := make([]string, 0, len(b.Fields))\n\tjsonFields := make(map[string]map[string]string)\n\n\tfor i := 0; i < len(b.Fields); i++ {\n\t\tif b.isKeyTable && b.Fields[i] == \"ecosystem\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.Contains(b.Fields[i], `->`) {\n\t\t\tcolfield := strings.Split(b.Fields[i], `->`)\n\t\t\tif len(colfield) == 2 {\n\t\t\t\tif jsonFields[colfield[0]] == nil {\n\t\t\t\t\tjsonFields[colfield[0]] = make(map[string]string)\n\t\t\t\t}\n\t\t\t\tjsonFields[colfield[0]][colfield[1]] = escapeSingleQuotes(b.stringValues[i])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif syspar.IsByteColumn(b.Table, b.Fields[i]) && len(b.stringValues[i]) != 0 {\n\t\t\texpressions = append(expressions, b.Fields[i]+\"=\"+toSQLHexExpr(b.stringValues[i]))\n\t\t} else if b.Fields[i][:1] == \"+\" || b.Fields[i][:1] == \"-\" {\n\t\t\texpressions = append(expressions, toArithmeticUpdateExpr(b.Fields[i], b.stringValues[i]))\n\t\t} else if b.stringValues[i] == `NULL` {\n\t\t\texpressions = append(expressions, b.Fields[i]+\"= NULL\")\n\t\t} else if strings.HasPrefix(b.Fields[i], prefTimestampSpace) {\n\t\t\texpressions = append(expressions, toTimestampUpdateExpr(b.Fields[i], b.stringValues[i]))\n\t\t} else if strings.HasPrefix(b.stringValues[i], prefTimestampSpace) {\n\t\t\texpressions = append(expressions, b.Fields[i]+`= timestamp '`+escapeSingleQuotes(b.stringValues[i][len(`timestamp `):])+`'`)\n\t\t} else {\n\t\t\texpressions = append(expressions, `\"`+b.Fields[i]+`\"='`+escapeSingleQuotes(b.stringValues[i])+`'`)\n\t\t}\n\t}\n\tvar jsonColumnArr []string\n\tfor name := range jsonFields {\n\t\tjsonColumnArr = append(jsonColumnArr, name)\n\t}\n\tsort.Strings(jsonColumnArr)\n\tfor _, name := range jsonColumnArr {\n\t\tval := jsonFields[name]\n\t\tvar initial string\n\t\tout, err := json.Marshal(val)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.JSONMarshallError}).Error(\"marshalling update columns for jsonb\")\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif len(logData[name]) > 0 && logData[name] != `NULL` {\n\t\t\tinitial = name\n\t\t} else {\n\t\t\tinitial = `'{}'`\n\t\t}\n\n\t\texpressions = append(expressions, fmt.Sprintf(`%s=%s::jsonb || '%s'::jsonb`, name, initial, string(out)))\n\t}\n\n\treturn strings.Join(expressions, \",\"), nil\n}\n\nfunc (b *SQLQueryBuilder) GetSQLInsertQuery(idGetter NextIDGetter) (string, error) {\n\tif err := b.Prepare(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tisID := false\n\tinsFields := []string{}\n\tinsValues := []string{}\n\tjsonFields := make(map[string]map[string]string)\n\n\tfor i := 0; i < len(b.Fields); i++ {\n\t\tif b.Fields[i] == `id` {\n\t\t\tisID = true\n\t\t\tb.tableID = escapeSingleQuotes(b.stringValues[i])\n\t\t}\n\n\t\tif strings.Contains(b.Fields[i], `->`) {\n\t\t\tcolfield := strings.Split(b.Fields[i], `->`)\n\t\t\tif len(colfield) == 2 {\n\t\t\t\tif jsonFields[colfield[0]] == nil {\n\t\t\t\t\tjsonFields[colfield[0]] = make(map[string]string)\n\t\t\t\t}\n\t\t\t\tjsonFields[colfield[0]][colfield[1]] = escapeSingleQuotes(b.stringValues[i])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tinsFields = append(insFields, toSQLField(b.Fields[i]))\n\t\tinsValues = append(insValues, b.toSQLValue(b.stringValues[i], b.Fields[i]))\n\t}\n\n\tvar jsonColumnArr []string\n\tfor name := range jsonFields {\n\t\tjsonColumnArr = append(jsonColumnArr, name)\n\t}\n\tsort.Strings(jsonColumnArr)\n\tfor _, name := range jsonColumnArr {\n\t\tval := jsonFields[name]\n\t\tout, err := json.Marshal(val)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.JSONMarshallError}).Error(\"marshalling update columns for jsonb\")\n\t\t\treturn \"\", err\n\t\t}\n\t\tinsFields = append(insFields, name)\n\t\tinsValues = append(insValues, fmt.Sprintf(`'%s'::jsonb`, string(out)))\n\t}\n\n\tif !isID {\n\t\tid, err := idGetter.GetNextID(b.Table)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tb.tableID = converter.Int64ToStr(id)\n\t\tinsFields = append(insFields, `id`)\n\t\tinsValues = append(insValues, wrapString(b.tableID, \"'\"))\n\t}\n\n\tflds := strings.Join(insFields, \",\")\n\tvls := strings.Join(insValues, \",\")\n\n\treturn fmt.Sprintf(`INSERT INTO \"%s\" (%s) VALUES (%s)`, b.Table, flds, vls), nil\n}\n\nfunc (b SQLQueryBuilder) GenerateRollBackInfoString(logData map[string]string) (string, error) {\n\trollbackInfo := make(map[string]string)\n\tfor k, v := range logData {\n\t\tvar eco bool\n\t\tidNames := strings.SplitN(b.Table, `_`, 2)\n\t\tif len(idNames) == 2 {\n\t\t\tb.keyName = idNames[1]\n\t\t\tif b.KeyTableChkr.IsKeyTable(b.keyName) {\n\t\t\t\teco = true\n\t\t\t}\n\t\t}\n\t\tif k == `id` || (b.isKeyTable && !eco) {\n\t\t\tcontinue\n\t\t}\n\t\trollbackInfo[k] = v\n\t}\n\n\tjsonRollbackInfo, err := json.Marshal(rollbackInfo)\n\tif err != nil {\n\t\tb.Logger.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marshalling rollback info to json\")\n\t\treturn \"\", err\n\t}\n\n\treturn string(jsonRollbackInfo), nil\n}\n\nfunc (b SQLQueryBuilder) toSQLValue(rawValue, rawField string) string {\n\tif syspar.IsByteColumn(b.Table, rawField) && len(rawValue) != 0 {\n\t\treturn toSQLHexExpr(rawValue)\n\t}\n\n\tif rawValue == `NULL` {\n\t\treturn `NULL`\n\t}\n\n\tif strings.HasPrefix(rawField, prefTimestamp) {\n\t\treturn toWrapedTimestamp(rawValue)\n\t}\n\n\tif strings.HasPrefix(rawValue, prefTimestamp) {\n\t\treturn toTimestamp(rawValue)\n\t}\n\n\treturn wrapString(escapeSingleQuotes(rawValue), \"'\")\n}\n\nfunc (b SQLQueryBuilder) normalizeValues() error {\n\tfor i, v := range b.FieldValues {\n\t\tswitch val := v.(type) {\n\t\tcase string:\n\t\t\tif strings.HasPrefix(strings.TrimSpace(val), prefTimestamp) {\n\t\t\t\tif err := CheckNow(val); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(b.Fields) > i && syspar.IsByteColumn(b.Table, b.Fields[i]) {\n\t\t\t\tif vbyte, err := hex.DecodeString(val); err == nil {\n\t\t\t\t\tb.FieldValues[i] = vbyte\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc isParamsContainsEcosystem(fields []string, ivalues []any) (bool, int) {\n\tecosysIndx := getFieldIndex(fields, `ecosystem`)\n\tif ecosysIndx >= 0 && len(ivalues) > ecosysIndx && converter.StrToInt64(fmt.Sprint(ivalues[ecosysIndx])) > 0 {\n\t\treturn true, ecosysIndx\n\t}\n\n\treturn false, -1\n}\n\nfunc toSQLHexExpr(value string) string {\n\treturn fmt.Sprintf(\" decode('%s','HEX')\", hex.EncodeToString([]byte(value)))\n}\n\nfunc toArithmeticUpdateExpr(field, value string) string {\n\treturn field[1:] + \"=\" + field[1:] + field[:1] + escapeSingleQuotes(value)\n}\n\nfunc toTimestampUpdateExpr(field, value string) string {\n\treturn field[len(prefTimestampSpace):] + `= to_timestamp('` + escapeSingleQuotes(value) + `')`\n}\n\nfunc toWrapedTimestamp(value string) string {\n\treturn `to_timestamp('` + escapeSingleQuotes(value) + `')`\n}\n\nfunc toTimestamp(value string) string {\n\treturn prefTimestampSpace + wrapString(escapeSingleQuotes(value[len(prefTimestampSpace):]), \"'\")\n}\n\nfunc toSQLField(rawField string) string {\n\tif rawField[:1] == \"+\" || rawField[:1] == \"-\" {\n\t\treturn rawField[1:]\n\t}\n\n\tif strings.HasPrefix(rawField, prefTimestampSpace) {\n\t\treturn rawField[len(prefTimestampSpace):]\n\t}\n\n\tif strings.Contains(rawField, `->`) {\n\t\treturn rawField[:strings.Index(rawField, `->`)]\n\t}\n\n\treturn wrapString(rawField, `\"`)\n}\n\nfunc wrapString(raw, wrapper string) string {\n\treturn wrapper + raw + wrapper\n}\n\nfunc escapeSingleQuotes(val string) string {\n\treturn strings.Replace(val, `'`, `''`, -1)\n}\n\n// CheckNow allows check if the content contains postgres NOW()\nfunc CheckNow(inputs ...string) error {\n\tfor _, item := range inputs {\n\t\tif checkNowRE.Match([]byte(strings.ToLower(item))) {\n\t\t\treturn ErrNow\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getFieldIndex(fields []string, name string) int {\n\tfor i, v := range fields {\n\t\tif strings.ToLower(v) == name {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\nfunc (b *SQLQueryBuilder) GetEcosystem() string {\n\treturn b.keyEcosystem\n}\n\nfunc (b *SQLQueryBuilder) IsEmptyWhere() bool {\n\treturn len(b.whereExpr) == 0\n}\n"
  },
  {
    "path": "packages/storage/sqldb/queryBuilder/query_builder_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage queryBuilder\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// query=\"SELECT ,,,id,amount,\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\\"ecosystem\\\"\n// FROM \\\"1_keys\\\" \\nWHERE  AND id = -6752330173818123413 AND ecosystem = '1'\\n\"\n\n// fields=\"[+amount]\"\n// values=\"[2912910000000]\"\n\n// whereF=\"[id]\"\n// whereV=\"[-6752330173818123413]\"\n\ntype TestKeyTableChecker struct {\n\tVal bool\n}\n\nfunc (tc TestKeyTableChecker) IsKeyTable(tableName string) bool {\n\treturn tc.Val\n}\nfunc TestSqlFields(t *testing.T) {\n\tqb := SQLQueryBuilder{\n\t\tEntry:        log.WithFields(log.Fields{\"mod\": \"test\"}),\n\t\tTable:        \"1_keys\",\n\t\tFields:       []string{\"+amount\"},\n\t\tFieldValues:  []any{2912910000000},\n\t\tWhere:        types.LoadMap(map[string]any{`id`: `-6752330173818123413`}),\n\t\tKeyTableChkr: TestKeyTableChecker{true},\n\t}\n\n\tfields, err := qb.GetSQLSelectFieldsExpr()\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tfmt.Println(fields)\n}\n"
  },
  {
    "path": "packages/storage/sqldb/queryBuilder/where.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage queryBuilder\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\nvar (\n\terrWhereFalse = errors.New(`false result`)\n)\n\nfunc PrepareWhere(where string) string {\n\twhereStr := where\n\twhere = strings.Replace(where, \"->\", \";\", -1)\n\twhereSlice := regexp.MustCompile(`;([\\w\\-]+)`).FindAllStringSubmatchIndex(where, -1)\n\tstartWhere := 0\n\tout := ``\n\tfor i := 0; i < len(whereSlice); i++ {\n\t\tslice := whereSlice[i]\n\t\tif len(slice) != 4 {\n\t\t\tcontinue\n\t\t}\n\t\tif i < len(whereSlice)-1 && slice[1] == whereSlice[i+1][0] {\n\t\t\tcolsWhere := []string{where[slice[2]:slice[3]]}\n\t\t\tfrom := slice[0]\n\t\t\tfor i < len(whereSlice)-1 && slice[1] == whereSlice[i+1][0] {\n\t\t\t\ti++\n\t\t\t\tslice = whereSlice[i]\n\t\t\t\tif len(slice) != 4 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcolsWhere = append(colsWhere, where[slice[2]:slice[3]])\n\t\t\t}\n\t\t\tout += fmt.Sprintf(`%s::jsonb#>>'{%s}'`, where[startWhere:from], strings.Join(colsWhere, `,`))\n\t\t\tstartWhere = slice[3]\n\t\t} else {\n\t\t\tout += fmt.Sprintf(`%s->>'%s'`, where[startWhere:slice[0]], where[slice[2]:slice[3]])\n\t\t\tstartWhere = slice[3]\n\t\t}\n\t}\n\tif len(out) > 0 {\n\t\treturn out + where[startWhere:]\n\t}\n\treturn whereStr\n}\n\nfunc GetWhere(inWhere *types.Map) (string, error) {\n\tvar (\n\t\twhere string\n\t\tcond  []string\n\t)\n\tif inWhere == nil {\n\t\tinWhere = types.NewMap()\n\t}\n\tescape := func(value any) string {\n\t\treturn strings.Replace(fmt.Sprint(value), `'`, `''`, -1)\n\t}\n\toper := func(action string, v any) (string, error) {\n\t\tswitch value := v.(type) {\n\t\tdefault:\n\t\t\treturn fmt.Sprintf(`%s '%s'`, action, escape(value)), nil\n\t\t}\n\t}\n\tlike := func(pattern string, v any) (string, error) {\n\t\tswitch value := v.(type) {\n\t\tdefault:\n\t\t\treturn fmt.Sprintf(pattern, escape(value)), nil\n\t\t}\n\t}\n\tin := func(action string, v any) (ret string, err error) {\n\t\tswitch value := v.(type) {\n\t\tcase string:\n\t\t\tif len(value) == 0 {\n\t\t\t\treturn `false`, errWhereFalse\n\t\t\t}\n\t\t\tret = fmt.Sprintf(`%s ('%s')`, action, value)\n\t\tcase []any:\n\t\t\tvar list []string\n\t\t\tfor _, ival := range value {\n\t\t\t\tlist = append(list, escape(ival))\n\t\t\t}\n\t\t\tif len(list) > 0 {\n\t\t\t\tret = fmt.Sprintf(`%s ('%s')`, action, strings.Join(list, `', '`))\n\t\t\t} else {\n\t\t\t\treturn `false`, errWhereFalse\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\tlogic := func(action string, v any) (ret string, err error) {\n\t\tswitch value := v.(type) {\n\t\tcase []any:\n\t\t\tvar list []string\n\t\t\tfor _, ival := range value {\n\t\t\t\tswitch avalue := ival.(type) {\n\t\t\t\tcase *types.Map:\n\t\t\t\t\twhere, err := GetWhere(avalue)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn ``, err\n\t\t\t\t\t}\n\t\t\t\t\tif len(where) > 0 {\n\t\t\t\t\t\tlist = append(list, where)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(list) > 0 {\n\t\t\t\tret = fmt.Sprintf(`(%s)`, strings.Join(list, ` `+action+` `))\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\tfor _, key := range inWhere.Keys() {\n\t\tv, _ := inWhere.Get(key)\n\t\tkey = PrepareWhere(converter.Sanitize(strings.ToLower(key), `->$`))\n\t\tswitch key {\n\t\tcase `$like`:\n\t\t\treturn like(`like '%%%s%%'`, v)\n\t\tcase `$end`:\n\t\t\treturn like(`like '%%%s'`, v)\n\t\tcase `$begin`:\n\t\t\treturn like(`like '%s%%'`, v)\n\t\tcase `$ilike`:\n\t\t\treturn like(`ilike '%%%s%%'`, v)\n\t\tcase `$iend`:\n\t\t\treturn like(`ilike '%%%s'`, v)\n\t\tcase `$ibegin`:\n\t\t\treturn like(`ilike '%s%%'`, v)\n\t\tcase `$and`:\n\t\t\ticond, err := logic(`and`, v)\n\t\t\tif err != nil {\n\t\t\t\treturn ``, err\n\t\t\t}\n\t\t\tcond = append(cond, icond)\n\t\tcase `$or`:\n\t\t\ticond, err := logic(`or`, v)\n\t\t\tif err != nil {\n\t\t\t\treturn ``, err\n\t\t\t}\n\t\t\tcond = append(cond, icond)\n\t\tcase `$in`:\n\t\t\treturn in(`in`, v)\n\t\tcase `$nin`:\n\t\t\treturn in(`not in`, v)\n\t\tcase `$eq`:\n\t\t\treturn oper(`=`, v)\n\t\tcase `$neq`:\n\t\t\treturn oper(`!=`, v)\n\t\tcase `$gt`:\n\t\t\treturn oper(`>`, v)\n\t\tcase `$gte`:\n\t\t\treturn oper(`>=`, v)\n\t\tcase `$lt`:\n\t\t\treturn oper(`<`, v)\n\t\tcase `$lte`:\n\t\t\treturn oper(`<=`, v)\n\t\tdefault:\n\t\t\tif !strings.Contains(key, `>`) && len(key) > 0 {\n\t\t\t\tkey = `\"` + key + `\"`\n\t\t\t}\n\t\t\tswitch value := v.(type) {\n\t\t\tcase []any:\n\t\t\t\tvar acond []string\n\t\t\t\tfor _, iarr := range value {\n\t\t\t\t\tswitch avalue := iarr.(type) {\n\t\t\t\t\tcase *types.Map:\n\t\t\t\t\t\tret, err := GetWhere(avalue)\n\t\t\t\t\t\tif err == errWhereFalse {\n\t\t\t\t\t\t\tacond = append(acond, ret)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn ``, err\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tacond = append(acond, fmt.Sprintf(`(%s %s)`, key, ret))\n\t\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tacond = append(acond, fmt.Sprintf(`%s = '%s'`, key, escape(avalue)))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif len(acond) > 0 {\n\t\t\t\t\tcond = append(cond, fmt.Sprintf(`(%s)`, strings.Join(acond, ` and `)))\n\t\t\t\t}\n\t\t\tcase *types.Map:\n\t\t\t\tret, err := GetWhere(value)\n\t\t\t\tif err == errWhereFalse {\n\t\t\t\t\tcond = append(cond, ret)\n\t\t\t\t} else {\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn ``, err\n\t\t\t\t\t}\n\t\t\t\t\tcond = append(cond, fmt.Sprintf(`(%s %s)`, key, ret))\n\t\t\t\t}\n\t\t\tcase []byte:\n\t\t\t\tcond = append(cond, fmt.Sprintf(`%s = %s`, key, fmt.Sprintf(\" decode('%x','HEX')\", value)))\n\t\t\tdefault:\n\t\t\t\tival := escape(value)\n\t\t\t\tif ival == `$isnull` {\n\t\t\t\t\tival = fmt.Sprintf(`%s is null`, key)\n\t\t\t\t} else {\n\t\t\t\t\tival = fmt.Sprintf(`%s = '%s'`, key, ival)\n\t\t\t\t}\n\t\t\t\tcond = append(cond, ival)\n\t\t\t}\n\t\t}\n\t}\n\tif len(cond) > 0 {\n\t\twhere = strings.Join(cond, ` and `)\n\t\tif err := CheckNow(where); err != nil {\n\t\t\treturn ``, err\n\t\t}\n\t}\n\treturn where, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/querycost/explain.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage querycost\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// explainQueryCost is counting query execution time\nfunc explainQueryCost(dbTx *sqldb.DbTransaction, withAnalyze bool, query string, args ...any) (int64, error) {\n\tvar planStr string\n\texplainTpl := \"EXPLAIN (FORMAT JSON) %s\"\n\tif withAnalyze {\n\t\texplainTpl = \"EXPLAIN ANALYZE (FORMAT JSON) %s\"\n\t}\n\terr := sqldb.GetDB(dbTx).Raw(fmt.Sprintf(explainTpl, query), args...).Row().Scan(&planStr)\n\tswitch {\n\tcase err == sql.ErrNoRows:\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"query\": query}).Error(\"no rows while explaining query\")\n\t\treturn 0, errors.New(\"No rows\")\n\tcase err != nil:\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"query\": query}).Error(\"error explaining query\")\n\t\treturn 0, err\n\t}\n\tvar queryPlan []map[string]any\n\tdec := json.NewDecoder(strings.NewReader(planStr))\n\tdec.UseNumber()\n\tif err := dec.Decode(&queryPlan); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"decoding query plan from JSON\")\n\t\treturn 0, err\n\t}\n\tif len(queryPlan) == 0 {\n\t\tlog.Error(\"Query plan is empty\")\n\t\treturn 0, errors.New(\"Query plan is empty\")\n\t}\n\tfirstNode := queryPlan[0]\n\tvar plan any\n\tvar ok bool\n\tif plan, ok = firstNode[\"Plan\"]; !ok {\n\t\tlog.Error(\"No Plan key in result\")\n\t\treturn 0, errors.New(\"No Plan key in result\")\n\t}\n\n\tplanMap, ok := plan.(map[string]any)\n\tif !ok {\n\t\tlog.Error(\"Plan is not map[string]interface{}\")\n\t\treturn 0, errors.New(\"Plan is not map[string]interface{}\")\n\t}\n\n\ttotalCost, ok := planMap[\"Total Cost\"]\n\tif !ok {\n\t\treturn 0, errors.New(\"PlanMap has no TotalCost\")\n\t}\n\n\ttotalCostNum, ok := totalCost.(json.Number)\n\tif !ok {\n\t\tlog.Error(\"PlanMap has no TotalCost\")\n\t\treturn 0, errors.New(\"Total cost is not a number\")\n\t}\n\n\ttotalCostF64, err := totalCostNum.Float64()\n\tif err != nil {\n\t\tlog.Error(\"Total cost is not a number\")\n\t\treturn 0, err\n\t}\n\treturn int64(totalCostF64), nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/querycost/formula.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage querycost\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tSelect = \"select\"\n\tInsert = \"insert\"\n\tUpdate = \"update\"\n\tDelete = \"delete\"\n\n\tSet  = \"set\"\n\tFrom = \"from\"\n\tInto = \"into\"\n\n\tQuote  = `\"`\n\tLparen = \"(\"\n)\n\nconst (\n\tSelectCost = 1\n\tUpdateCost = 1\n\tInsertCost = 1\n\tDeleteCost = 1\n\n\tSelectRowCoeff = 0.0001\n\tInsertRowCoeff = 0.0001\n\tDeleteRowCoeff = 0.0001\n\tUpdateRowCoeff = 0.0001\n)\n\nvar FromStatementMissingError = errors.New(\"FROM statement missing\")\nvar DeleteMinimumThreeFieldsError = errors.New(\"DELETE query must consist minimum of 3 fields\")\nvar SetStatementMissingError = errors.New(\"SET statement missing\")\nvar IntoStatementMissingError = errors.New(\"INTO statement missing\")\nvar UnknownQueryTypeError = errors.New(\"Unknown query type\")\n\nfunc strSliceIndex(fields []string, fieldToFind string) (index int) {\n\tfor i, field := range fields {\n\t\tif field == fieldToFind {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\ntype TableRowCounter interface {\n\tRowCount(*sqldb.DbTransaction, string) (int64, error)\n}\n\ntype DBCountQueryRowCounter struct {\n}\n\nfunc (d *DBCountQueryRowCounter) RowCount(transaction *sqldb.DbTransaction, tableName string) (int64, error) {\n\tcount, err := transaction.GetRecordsCountTx(tableName, ``)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err, \"table\": tableName}).Error(\"Getting record count from table\")\n\t}\n\treturn count, err\n}\n\ntype FormulaQueryCoster struct {\n\trowCounter TableRowCounter\n}\n\ntype QueryType interface {\n\tGetTableName() (string, error)\n\tCalculateCost(int64) int64\n}\n\ntype SelectQueryType string\n\nfunc (s SelectQueryType) GetTableName() (string, error) {\n\tqueryFields := strings.Fields(string(s))\n\tfromFieldIndex := strSliceIndex(queryFields, From)\n\tif fromFieldIndex == 0 {\n\t\treturn \"\", nil\n\t}\n\treturn strings.Trim(queryFields[fromFieldIndex+1], Quote), nil\n}\n\nfunc (s SelectQueryType) CalculateCost(rowCount int64) int64 {\n\treturn SelectCost + int64(SelectRowCoeff*float64(rowCount))\n}\n\ntype UpdateQueryType string\n\nfunc (s UpdateQueryType) GetTableName() (string, error) {\n\tqueryFields := strings.Fields(string(s))\n\tsetFieldIndex := strSliceIndex(queryFields, Set)\n\tif setFieldIndex == 0 {\n\t\treturn \"\", SetStatementMissingError\n\t}\n\treturn strings.Trim(queryFields[setFieldIndex-1], Quote), nil\n}\n\nfunc (s UpdateQueryType) CalculateCost(rowCount int64) int64 {\n\treturn UpdateCost + int64(UpdateRowCoeff*float64(rowCount))\n}\n\ntype InsertQueryType string\n\nfunc (s InsertQueryType) GetTableName() (string, error) {\n\tqueryFields := strings.Fields(string(s))\n\tintoFieldIndex := strSliceIndex(queryFields, Into)\n\tif intoFieldIndex == 0 {\n\t\treturn \"\", IntoStatementMissingError\n\t}\n\ttableNameValuesField := queryFields[intoFieldIndex+1]\n\ttableName := \"\"\n\tlparenIndex := strings.Index(tableNameValuesField, Lparen)\n\tif lparenIndex > 0 {\n\t\ttableName = tableNameValuesField[:lparenIndex]\n\t} else {\n\t\ttableName = tableNameValuesField\n\t}\n\treturn strings.Trim(tableName, Quote), nil\n}\n\nfunc (s InsertQueryType) CalculateCost(rowCount int64) int64 {\n\treturn InsertCost\n}\n\ntype DeleteQueryType string\n\nfunc (s DeleteQueryType) GetTableName() (string, error) {\n\tqueryFields := strings.Fields(string(s))\n\tfromFieldIndex := strSliceIndex(queryFields, From)\n\tif fromFieldIndex == 0 {\n\t\treturn \"\", FromStatementMissingError\n\t}\n\t// DELETE FROM table is minimum\n\tif len(queryFields) < 3 {\n\t\treturn \"\", DeleteMinimumThreeFieldsError\n\t}\n\treturn strings.Trim(queryFields[fromFieldIndex+1], Quote), nil\n}\n\nfunc (s DeleteQueryType) CalculateCost(rowCount int64) int64 {\n\treturn DeleteCost + int64(DeleteRowCoeff*float64(rowCount))\n}\n\nfunc (f *FormulaQueryCoster) QueryCost(transaction *sqldb.DbTransaction, query string, args ...any) (int64, error) {\n\tcleanedQuery := strings.TrimSpace(strings.ToLower(query))\n\tvar queryType QueryType\n\tswitch {\n\tcase strings.HasPrefix(cleanedQuery, Select):\n\t\tqueryType = SelectQueryType(cleanedQuery)\n\tcase strings.HasPrefix(cleanedQuery, Insert):\n\t\tqueryType = InsertQueryType(cleanedQuery)\n\tcase strings.HasPrefix(cleanedQuery, Update):\n\t\tqueryType = UpdateQueryType(cleanedQuery)\n\tcase strings.HasPrefix(cleanedQuery, Delete):\n\t\tqueryType = DeleteQueryType(cleanedQuery)\n\tdefault:\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"query\": query}).Error(\"parsing sql query\")\n\t\treturn 0, UnknownQueryTypeError\n\t}\n\ttableName, err := queryType.GetTableName()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ParseError, \"query\": query, \"error\": err}).Error(\"getting table name from sql query\")\n\t\treturn 0, err\n\t}\n\trowCount, err := f.rowCounter.RowCount(transaction, tableName)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn queryType.CalculateCost(rowCount), nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/querycost/formula_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage querycost\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n)\n\ntype TestTableRowCounter struct {\n}\n\nconst tableRowCount = 10000\n\nfunc (t *TestTableRowCounter) RowCount(tx *sqldb.DbTransaction, tableName string) (int64, error) {\n\tif tableName == \"small\" {\n\t\treturn tableRowCount, nil\n\t}\n\treturn 0, errors.New(\"Unknown table\")\n}\n\ntype QueryCostByFormulaTestSuite struct {\n\tsuite.Suite\n\tqueryCoster QueryCoster\n}\n\nfunc (s *QueryCostByFormulaTestSuite) SetupTest() {\n\ts.queryCoster = &FormulaQueryCoster{&TestTableRowCounter{}}\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestQueryCostUnknownQueryType() {\n\t_, err := s.queryCoster.QueryCost(nil, \"UNSELECT * FROM name\")\n\tassert.Error(s.T(), err)\n\tassert.Equal(s.T(), err, UnknownQueryTypeError)\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromSelectNoTable() {\n\ttableName, err := SelectQueryType(\"select 3\").GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"\")\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromSelect() {\n\ttableName, err := SelectQueryType(\"select a from keys where 3=1\").GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"keys\")\n\ttableName, err = SelectQueryType(`select a,  b,  c from \"1_keys\" where 3=1`).GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"1_keys\")\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromInsertNoInto() {\n\t_, err := InsertQueryType(`insert \"1_keys\"(id) values (1)`).GetTableName()\n\tassert.Error(s.T(), err)\n\tassert.Equal(s.T(), err, IntoStatementMissingError)\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromInsert() {\n\ttableName, err := InsertQueryType(\"insert into keys(a,b,c) values (1,2,3)\").GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"keys\")\n\ttableName, err = InsertQueryType(`insert into \"1_keys\" (a,b,c) values (1,2,3)`).GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"1_keys\")\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromUpdateNoSet() {\n\t_, err := UpdateQueryType(`update keys a = b where id = 1`).GetTableName()\n\tassert.Error(s.T(), err)\n\tassert.Equal(s.T(), err, SetStatementMissingError)\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromUpdate() {\n\ttableName, err := UpdateQueryType(\"update keys set a = 1 where id = 2\").GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"keys\")\n\ttableName, err = UpdateQueryType(`update \"1_keys\" set a = 1`).GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"1_keys\")\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromDeleteNoFrom() {\n\t_, err := DeleteQueryType(`delete table where id = 1`).GetTableName()\n\tassert.Error(s.T(), err)\n\tassert.Equal(s.T(), err, FromStatementMissingError)\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromDeleteNoTable() {\n\t_, err := DeleteQueryType(`delete from`).GetTableName()\n\tassert.Error(s.T(), err)\n\tassert.Equal(s.T(), err, DeleteMinimumThreeFieldsError)\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestGetTableNameFromDelete() {\n\ttableName, err := DeleteQueryType(\"delete from keys\").GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"keys\")\n\ttableName, err = DeleteQueryType(`delete from \"1_keys\" where a = 1`).GetTableName()\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), tableName, \"1_keys\")\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestQueryCostSelect() {\n\tcost, err := s.queryCoster.QueryCost(nil, \"SELECT * FROM small WHERE id = ?\", 3)\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), cost, SelectQueryType(\"\").CalculateCost(tableRowCount))\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestQueryCostUpdate() {\n\tcost, err := s.queryCoster.QueryCost(nil, \"UPDATE small SET a = ?\", 3)\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), cost, UpdateQueryType(\"\").CalculateCost(tableRowCount))\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestQueryCostDelete() {\n\tcost, err := s.queryCoster.QueryCost(nil, \"DELETE FROM small\")\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), cost, DeleteQueryType(\"\").CalculateCost(tableRowCount))\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestQueryCostInsert() {\n\tcost, err := s.queryCoster.QueryCost(nil, \"INSERT INTO small(a,b) VALUES (1,2)\")\n\tassert.Nil(s.T(), err)\n\tassert.Equal(s.T(), cost, InsertQueryType(\"\").CalculateCost(tableRowCount))\n}\n\nfunc (s *QueryCostByFormulaTestSuite) TestQueryCostInsertWrongTable() {\n\t_, err := s.queryCoster.QueryCost(nil, \"INSERT INTO unknown(a,b) VALUES (1,2)\")\n\tassert.Error(s.T(), err)\n}\n\nfunc TestQueryCostFormula(t *testing.T) {\n\tsuite.Run(t, new(QueryCostByFormulaTestSuite))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/querycost/querycost.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage querycost\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\ntype QueryCosterType int\n\nconst (\n\tExplainQueryCosterType        QueryCosterType = iota\n\tExplainAnalyzeQueryCosterType QueryCosterType = iota\n\tFormulaQueryCosterType        QueryCosterType = iota\n)\n\ntype QueryCoster interface {\n\tQueryCost(*sqldb.DbTransaction, string, ...any) (int64, error)\n}\n\ntype ExplainQueryCoster struct {\n}\n\nfunc (*ExplainQueryCoster) QueryCost(transaction *sqldb.DbTransaction, query string, args ...any) (int64, error) {\n\treturn explainQueryCost(transaction, true, query, args...)\n}\n\ntype ExplainAnalyzeQueryCoster struct {\n}\n\nfunc (*ExplainAnalyzeQueryCoster) QueryCost(transaction *sqldb.DbTransaction, query string, args ...any) (int64, error) {\n\treturn explainQueryCost(transaction, true, query, args...)\n}\n\nfunc GetQueryCoster(tp QueryCosterType) QueryCoster {\n\tswitch tp {\n\tcase ExplainQueryCosterType:\n\t\treturn &ExplainQueryCoster{}\n\tcase ExplainAnalyzeQueryCosterType:\n\t\treturn &ExplainAnalyzeQueryCoster{}\n\tcase FormulaQueryCosterType:\n\t\treturn &FormulaQueryCoster{&DBCountQueryRowCounter{}}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/queue_block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\n// QueueBlock is model\ntype QueueBlock struct {\n\tHash        []byte `gorm:\"primary_key;not null\"`\n\tBlockID     int64  `gorm:\"not null\"`\n\tHonorNodeID int64  `gorm:\"not null\"`\n}\n\n// Get is retrieving model from database\nfunc (qb *QueueBlock) Get() (bool, error) {\n\treturn isFound(DBConn.First(qb))\n}\n\n// GetQueueBlockByHash is retrieving blocks queue by hash\nfunc (qb *QueueBlock) GetQueueBlockByHash(hash []byte) (bool, error) {\n\treturn isFound(DBConn.Where(\"hash = ?\", hash).First(qb))\n}\n\n// Delete is deleting queue\nfunc (qb *QueueBlock) Delete() error {\n\treturn DBConn.Delete(qb).Error\n}\n\n// DeleteQueueBlockByHash is deleting queue by hash\nfunc (qb *QueueBlock) DeleteQueueBlockByHash() error {\n\tquery := DBConn.Exec(\"DELETE FROM queue_blocks WHERE hash = ?\", qb.Hash)\n\treturn query.Error\n}\n\n// DeleteOldBlocks is deleting old blocks\nfunc (qb *QueueBlock) DeleteOldBlocks() error {\n\tquery := DBConn.Exec(\"DELETE FROM queue_blocks WHERE block_id <= ?\", qb.BlockID)\n\treturn query.Error\n}\n\n// Create is creating record of model\nfunc (qb *QueueBlock) Create() error {\n\treturn DBConn.Create(qb).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/queue_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/shopspring/decimal\"\n)\n\n// QueueTx is model\ntype QueueTx struct {\n\tHash     []byte          `gorm:\"primary_key;not null\"`\n\tData     []byte          `gorm:\"not null\"`\n\tFromGate int             `gorm:\"not null\"`\n\tExpedite decimal.Decimal `gorm:\"not null\"`\n\tTime     int64           `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (qt *QueueTx) TableName() string {\n\treturn \"queue_tx\"\n}\n\n// DeleteTx is deleting tx\nfunc (qt *QueueTx) DeleteTx(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Delete(qt).Error\n}\n\n// Save is saving model\nfunc (qt *QueueTx) Save(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Save(qt).Error\n}\n\n// Create is creating record of model\nfunc (qt *QueueTx) Create() error {\n\treturn DBConn.Create(qt).Error\n}\n\n// GetByHash is retrieving model from database by hash\nfunc (qt *QueueTx) GetByHash(dbTx *DbTransaction, hash []byte) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"hash = ?\", hash).First(qt))\n}\n\n// DeleteQueueTxByHash is deleting queue tx by hash\nfunc DeleteQueueTxByHash(dbTx *DbTransaction, hash []byte) (int64, error) {\n\tquery := GetDB(dbTx).Exec(\"DELETE FROM queue_tx WHERE hash = ?\", hash)\n\treturn query.RowsAffected, query.Error\n}\n\n// GetQueuedTransactionsCount counting queued transactions\nfunc GetQueuedTransactionsCount(hash []byte) (int64, error) {\n\tvar rowsCount int64\n\terr := DBConn.Table(\"queue_tx\").Where(\"hash = ?\", hash).Count(&rowsCount).Error\n\treturn rowsCount, err\n}\n\n// GetAllUnverifiedAndUnusedTransactions is returns all unverified and unused transaction\nfunc GetAllUnverifiedAndUnusedTransactions(dbTx *DbTransaction, limit int) ([]*QueueTx, error) {\n\tquery := `SELECT *\n\t\t  FROM (\n\t              SELECT data,\n\t                     hash,expedite,time\n\t              FROM queue_tx\n\t\t      UNION\n\t\t      SELECT data,\n\t\t\t     hash,expedite,time\n\t\t      FROM transactions\n\t\t      WHERE verified = 0 AND used = 0\n\t\t\t)  AS x ORDER BY expedite DESC,time ASC limit ?`\n\tvar result []*QueueTx\n\terr := GetDB(dbTx).Raw(query, limit).Scan(&result).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc DeleteQueueTxs(dbTx *DbTransaction, hs [][]byte) error {\n\tif len(hs) == 0 {\n\t\treturn nil\n\t}\n\treturn GetDB(dbTx).Delete(&QueueTx{}, hs).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/responecode.go",
    "content": "package sqldb\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nvar (\n\tdefaultStatus = http.StatusOK\n\t//ErrEcosystemNotFound = errors.New(\"Ecosystem not found\")\n\t//errContract          = errType{\"E_CONTRACT\", \"There is not %s contract\", http.StatusNotFound}\n\t//errDBNil             = errType{\"E_DBNIL\", \"DB is nil\", defaultStatus}\n\t//errDeletedKey        = errType{\"E_DELETEDKEY\", \"The key is deleted\", http.StatusForbidden}\n\t//errEcosystem         = errType{\"E_ECOSYSTEM\", \"Ecosystem %d doesn't exist\", defaultStatus}\n\t//errEmptyPublic       = errType{\"E_EMPTYPUBLIC\", \"Public key is undefined\", http.StatusBadRequest}\n\t//errKeyNotFound       = errType{\"E_KEYNOTFOUND\", \"Key has not been found\", http.StatusNotFound}\n\t//errEmptySign         = errType{\"E_EMPTYSIGN\", \"Signature is undefined\", defaultStatus}\n\t//errHashWrong         = errType{\"E_HASHWRONG\", \"Hash is incorrect\", http.StatusBadRequest}\n\t//errHashNotFound      = errType{\"E_HASHNOTFOUND\", \"Hash has not been found\", defaultStatus}\n\t//errHeavyPage         = errType{\"E_HEAVYPAGE\", \"This page is heavy\", defaultStatus}\n\t//errInstalled         = errType{\"E_INSTALLED\", \"Chain is already installed\", defaultStatus}\n\t//errInvalidWallet     = errType{\"E_INVALIDWALLET\", \"Wallet %s is not valid\", http.StatusBadRequest}\n\t//errLimitForsign      = errType{\"E_LIMITFORSIGN\", \"Length of forsign is too big (%d)\", defaultStatus}\n\t//errLimitTxSize       = errType{\"E_LIMITTXSIZE\", \"The size of tx is too big (%d)\", defaultStatus}\n\t//errNotFound          = errType{\"E_NOTFOUND\", \"Page not found\", http.StatusNotFound}\n\t//errNotFoundRecord    = errType{\"E_NOTFOUND\", \"Record not found\", http.StatusNotFound}\n\t//errParamNotFound     = errType{\"E_PARAMNOTFOUND\", \"Parameter %s has not been found\", http.StatusNotFound}\n\t//errPermission        = errType{\"E_PERMISSION\", \"Permission denied\", http.StatusUnauthorized}\n\t//errQuery             = errType{\"E_QUERY\", \"DB query is wrong\", http.StatusInternalServerError}\n\t//errRecovered         = errType{\"E_RECOVERED\", \"API recovered\", http.StatusInternalServerError}\n\t//errServer            = errType{\"E_SERVER\", \"Server error\", defaultStatus}\n\t//errSignature         = errType{\"E_SIGNATURE\", \"Signature is incorrect\", http.StatusBadRequest}\n\t//errUnknownSign       = errType{\"E_UNKNOWNSIGN\", \"Unknown signature\", defaultStatus}\n\t//errStateLogin        = errType{\"E_STATELOGIN\", \"%s is not a membership of ecosystem %s\", http.StatusForbidden}\n\t//errTableNotFound     = errType{\"E_TABLENOTFOUND\", \"Table %s has not been found\", http.StatusNotFound}\n\t//errToken             = errType{\"E_TOKEN\", \"Token is not valid\", defaultStatus}\n\t//errTokenExpired      = errType{\"E_TOKENEXPIRED\", \"Token is expired by %s\", http.StatusUnauthorized}\n\t//errUnauthorized      = errType{\"E_UNAUTHORIZED\", \"Unauthorized\", http.StatusUnauthorized}\n\t//errUndefineval       = errType{\"E_UNDEFINEVAL\", \"Value %s is undefined\", defaultStatus}\n\t//errUnknownUID        = errType{\"E_UNKNOWNUID\", \"Unknown uid\", defaultStatus}\n\t//errCLB               = errType{\"E_CLB\", \"Virtual Dedicated Ecosystem %d doesn't exist\", defaultStatus}\n\t//errCLBCreated        = errType{\"E_CLBCREATED\", \"Virtual Dedicated Ecosystem is already created\", http.StatusBadRequest}\n\t//errRequestNotFound   = errType{\"E_REQUESTNOTFOUND\", \"Request %s doesn't exist\", defaultStatus}\n\t//errUpdating          = errType{\"E_UPDATING\", \"Node is updating blockchain\", http.StatusServiceUnavailable}\n\t//errStopping          = errType{\"E_STOPPING\", \"Network is stopping\", http.StatusServiceUnavailable}\n\t//errNotImplemented    = errType{\"E_NOTIMPLEMENTED\", \"Not implemented\", http.StatusNotImplemented}\n\t//errParamMoneyDigit   = errType{\"E_PARAMMONEYDIGIT\", \"The number of decimal places cannot be exceeded ( %s )\", http.StatusBadRequest}\n\t//errDiffKey           = CodeType{\"E_DIFKEY\", \"Sender's key is different from tx key\", defaultStatus}\n\t//errBannded           = errType{\"E_BANNED\", \"The key is banned till %s\", http.StatusForbidden}\n\t//errCheckRole         = errType{\"E_CHECKROLE\", \"Access denied\", http.StatusForbidden}\n\t//errNewUser           = errType{\"E_NEWUSER\", \"Can't create a new user\", http.StatusUnauthorized}\n\tCodeSystembusy = CodeType{-1, \"System is busy\", http.StatusOK, \"\"}\n\tCodeSuccess    = CodeType{0, \"Success\", http.StatusOK, \"OK\"}\n\t//CodeFileNotExists         = CodeType{40001, \"File %s not exists\", http.StatusOK, \"\"}\n\t//CodeFileFormatNotSupports = CodeType{40002, \"File %s format is not supported\", http.StatusOK, \"\"}\n\tCodeIlgmediafiletype    = CodeType{40003, \"illegal media file type  \", http.StatusOK, \"\"}\n\tCodeIlgfiletype         = CodeType{40004, \"illegal file type  \", http.StatusOK, \"\"}\n\tCodeFilesize            = CodeType{40005, \"illegal file size  \", http.StatusOK, \"\"}\n\tCodeImagesize           = CodeType{40006, \"illegal image file size  \", http.StatusOK, \"\"}\n\tCodeVoicesize           = CodeType{40007, \"illegal voice file size  \", http.StatusOK, \"\"}\n\tCodeVideosize           = CodeType{40008, \"illegal video file size  \", http.StatusOK, \"\"}\n\tCodeRequestformat       = CodeType{40009, \"illegal request format  \", http.StatusOK, \"\"}\n\tCodeThumbnailfilesize   = CodeType{400010, \"illegal thumbnail file size  \", http.StatusOK, \"\"}\n\tCodeUrllength           = CodeType{400011, \"illegal URL length  \", http.StatusOK, \"\"}\n\tCodeMultimediafileempty = CodeType{400012, \"The multimedia file is empty  \", http.StatusOK, \"\"}\n\tCodePostpacketempty     = CodeType{400013, \"POST packet is empty \", http.StatusOK, \"\"}\n\tCodeContentempty        = CodeType{400014, \"The content of the graphic message is empty. \", http.StatusOK, \"\"}\n\tCodeTextcmpty           = CodeType{400015, \"text message content is empty \", http.StatusOK, \"\"}\n\tCodeMultimediasizelimit = CodeType{400016, \"multimedia file size exceeds limit \", http.StatusOK, \"\"}\n\tCodeParamNotNull        = CodeType{400017, \"Param  message content exceeds limit \", http.StatusOK, \"\"}\n\tCodeParamOutRange       = CodeType{400018, \"Param out of range \", http.StatusOK, \"\"}\n\tCodeParam               = CodeType{400019, \"Param error \", http.StatusOK, \"\"}\n\tCodeParamNotExists      = CodeType{400020, \"Param is exists  \", http.StatusOK, \"\"}\n\tCodeParamType           = CodeType{400021, \"Param type error \", http.StatusOK, \"\"}\n\tCodeParamKeyConflict    = CodeType{400022, \"Param Keyword conflict error \", http.StatusOK, \"\"}\n\tCodeRecordExists        = CodeType{400023, \"Record already exists  \", http.StatusOK, \"\"}\n\tCodeRecordNotExists     = CodeType{400024, \"Record not exists error  \", http.StatusOK, \"\"}\n\tCodeNewRecordNotRelease = CodeType{400025, \"New Record not Release error \", http.StatusOK, \"\"}\n\tCodeReleaseRule         = CodeType{400026, \"Release rule error  \", http.StatusOK, \"\"}\n\tCodeDeleteRule          = CodeType{400027, \"Delete Record  delete rule error  \", http.StatusOK, \"\"}\n\tCodeHelpDirNotExists    = CodeType{400028, \"Help parentdir  not exists error  \", http.StatusOK, \"\"}\n\n\tCodeDBfinderr     = CodeType{400029, \"DB find error   \", http.StatusOK, \"\"}\n\tCodeDBcreateerr   = CodeType{400030, \"DB create error  \", http.StatusOK, \"\"}\n\tCodeDBupdateerr   = CodeType{400031, \"DB update error  \", http.StatusOK, \"\"}\n\tCodeDBdeleteerr   = CodeType{400032, \"DB delete error  \", http.StatusOK, \"\"}\n\tCodeDBopertionerr = CodeType{400033, \"DB opertion error  \", http.StatusOK, \"\"}\n\tCodeJsonformaterr = CodeType{400034, \"Json format error  \", http.StatusOK, \"\"}\n\tCodeBodyformaterr = CodeType{400035, \"Body format error  \", http.StatusOK, \"\"}\n\n\tCodeFileNotExists = CodeType{400036, \"File not exists\", http.StatusOK, \"\"}\n\t//CodeFileFormatNotSupports = CodeType{40002, \"File %s format is not supported\", http.StatusOK, \"\"}\n\tCodeFileExists            = CodeType{400037, \"File already exists\", http.StatusOK, \"\"}\n\tCodeFileFormatNotSupports = CodeType{400038, \"File format is not supported\", http.StatusOK, \"\"}\n\tCodeFileCreated           = CodeType{400039, \"Create File is not supported \", http.StatusOK, \"\"}\n\tCodeFileOpen              = CodeType{400039, \"Open File is not supported\", http.StatusOK, \"\"}\n\tCodeCheckParam            = CodeType{400040, \"Param error: \", http.StatusOK, \"\"}\n\tCodeGenerateMine          = CodeType{400041, \"new miner generate faile \", http.StatusOK, \"\"}\n\tCodeImportMine            = CodeType{400042, \"import miner faile   \", http.StatusOK, \"\"}\n\tCodeBooltype              = CodeType{400043, \"bool type error  \", http.StatusOK, \"\"}\n\n\tCodeUpdateRule               = CodeType{400044, \"rule error  \", http.StatusOK, \"\"}\n\tCodePermissionDenied         = CodeType{400045, \"Permission denied  \", http.StatusOK, \"\"}\n\tCodeNotMineDevidBindActiveid = CodeType{400046, \"not mine devid boind Activeid  \", http.StatusOK, \"\"}\n\tCodeSignError                = CodeType{400047, \"sign err \", http.StatusOK, \"\"}\n\t//CodeNotMineDevidBindActiveid = CodeType{400046, \"not mine devid boind Activeid  \", http.StatusOK, \"\"}\n\t//CodeReleaseRule          = CodeType{400042, \"Release rule  conflict %s \", http.StatusOK, \"\"}\n\t//CodeGenerateMine          = CodeType{400041, \"new miner generate faile \", http.StatusOK, \"\"}\n\t//CodeGenerateMine          = CodeType{400041, \"new miner generate faile \", http.StatusOK, \"\"}\n)\n\ntype CodeType struct {\n\tCode    int    `json:\"code\"`\n\tMessage string `json:\"message\"`\n\tStatus  int    `json:\"status\"`\n\tMsg     string `json:\"msg\"`\n}\n\n//\ntype errType struct {\n\tErr     string `json:\"error\"`\n\tMessage string `json:\"msg\"`\n\tStatus  int    `json:\"-\"`\n}\n\nfunc (et errType) Error() string {\n\treturn et.Err\n}\n\nfunc (et errType) Errorf(v ...any) errType {\n\tet.Message = fmt.Sprintf(et.Message, v...)\n\treturn et\n}\n\nfunc (ct CodeType) Errorf(err error) CodeType {\n\tet, ok := err.(errType)\n\tif !ok {\n\t\tet.Message = err.Error()\n\t}\n\tct.Message = fmt.Sprintln(ct.Message, et.Message)\n\tct.Msg = http.StatusText(ct.Status)\n\treturn ct\n}\n\nfunc (ct CodeType) String(dat string) CodeType {\n\tct.Message += \" \" + dat\n\tct.Msg = http.StatusText(ct.Status)\n\treturn ct\n}\n\nfunc (ct CodeType) Success() CodeType {\n\tct.Msg = http.StatusText(ct.Status)\n\treturn ct\n}\n"
  },
  {
    "path": "packages/storage/sqldb/result.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"database/sql\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// SingleResult is a structure for the single result\ntype SingleResult struct {\n\tresult []byte\n\terr    error\n}\n\n// Single is retrieving single result\nfunc (dbTx *DbTransaction) Single(query string, args ...any) *SingleResult {\n\tvar result []byte\n\terr := GetDB(dbTx).Raw(query, args...).Row().Scan(&result)\n\tswitch {\n\tcase err == sql.ErrNoRows:\n\t\treturn &SingleResult{[]byte(\"\"), nil}\n\tcase err != nil:\n\t\treturn &SingleResult{[]byte(\"\"), err}\n\t}\n\treturn &SingleResult{result, nil}\n}\n\n// Int64 converts bytes to int64\nfunc (r *SingleResult) Int64() (int64, error) {\n\tif r.err != nil {\n\t\treturn 0, r.err\n\t}\n\treturn converter.BytesToInt64(r.result), nil\n}\n\n// Int converts bytes to int\nfunc (r *SingleResult) Int() (int, error) {\n\tif r.err != nil {\n\t\treturn 0, r.err\n\t}\n\treturn converter.BytesToInt(r.result), nil\n}\n\n// Float64 converts string to float64\nfunc (r *SingleResult) Float64() (float64, error) {\n\tif r.err != nil {\n\t\treturn 0, r.err\n\t}\n\treturn converter.StrToFloat64(string(r.result)), nil\n}\n\n// String returns string\nfunc (r *SingleResult) String() (string, error) {\n\tif r.err != nil {\n\t\treturn \"\", r.err\n\t}\n\treturn string(r.result), nil\n}\n\n// Bytes returns []byte\nfunc (r *SingleResult) Bytes() ([]byte, error) {\n\tif r.err != nil {\n\t\treturn []byte(\"\"), r.err\n\t}\n\treturn r.result, nil\n}\n\n// OneRow is storing one row result\ntype OneRow struct {\n\tresult map[string]string\n\tList   []map[string]string\n\terr    error\n}\n\n// String is extracts result from OneRow as string\nfunc (r *OneRow) String() (map[string]string, error) {\n\tif r.err != nil {\n\t\treturn r.result, r.err\n\t}\n\treturn r.result, nil\n}\n\n// Bytes is extracts result from OneRow as []byte\nfunc (r *OneRow) Bytes() (map[string][]byte, error) {\n\tresult := make(map[string][]byte)\n\tif r.err != nil {\n\t\treturn result, r.err\n\t}\n\tfor k, v := range r.result {\n\t\tresult[k] = []byte(v)\n\t}\n\treturn result, nil\n}\n\n// Int64 is extracts result from OneRow as int64\nfunc (r *OneRow) Int64() (map[string]int64, error) {\n\tresult := make(map[string]int64)\n\tif r.err != nil {\n\t\treturn result, r.err\n\t}\n\tfor k, v := range r.result {\n\t\tresult[k] = converter.StrToInt64(v)\n\t}\n\treturn result, nil\n}\n\n// Float64 is extracts result from OneRow as float64\nfunc (r *OneRow) Float64() (map[string]float64, error) {\n\tresult := make(map[string]float64)\n\tif r.err != nil {\n\t\treturn result, r.err\n\t}\n\tfor k, v := range r.result {\n\t\tresult[k] = converter.StrToFloat64(v)\n\t}\n\treturn result, nil\n}\n\n// Int is extracts result from OneRow as int\nfunc (r *OneRow) Int() (map[string]int, error) {\n\tresult := make(map[string]int)\n\tif r.err != nil {\n\t\treturn result, r.err\n\t}\n\tfor k, v := range r.result {\n\t\tresult[k] = converter.StrToInt(v)\n\t}\n\treturn result, nil\n}\n\n// GetAllTransaction is retrieve all query result rows\nfunc (dbTx *DbTransaction) GetAllTransaction(query string, countRows int, args ...any) ([]map[string]string, error) {\n\trequest := GetDB(dbTx).Raw(query, args...)\n\tif countRows > 0 {\n\t\trequest = request.Limit(countRows)\n\t}\n\trows, err := request.Rows()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s in query %s %s\", err, query, args)\n\t}\n\tdefer rows.Close()\n\tresult, err := getResult(rows, countRows)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s in query %s %s\", err, query, args)\n\t}\n\treturn result, nil\n}\n\n// GetOneRowTransaction returns one row from transactions\nfunc (dbTx *DbTransaction) GetOneRowTransaction(query string, args ...any) *OneRow {\n\tresult := make(map[string]string)\n\tall, err := dbTx.GetAllTransaction(query, -1, args...)\n\tif err != nil {\n\t\treturn &OneRow{result: result, err: fmt.Errorf(\"%s in query %s %s\", err, query, args)}\n\t}\n\tif len(all) == 0 {\n\t\treturn &OneRow{result: result, err: nil}\n\t}\n\treturn &OneRow{result: all[0], List: all, err: nil}\n}\n\n// GetOneRow returns one row\nfunc (dbTx *DbTransaction) GetOneRow(query string, args ...any) *OneRow {\n\treturn dbTx.GetOneRowTransaction(query, args...)\n}\n\nfunc (dbTx *DbTransaction) GetRows(tableName, columns string, offset, limit int) ([]map[string]string, error) {\n\tquery := GetDB(dbTx).Table(tableName).Order(\"id\").Offset(offset).Limit(limit)\n\tif len(columns) > 0 {\n\t\tcolumns = \"id,\" + columns\n\t\tquery = query.Select(columns)\n\t}\n\trows, err := query.Rows()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer rows.Close()\n\treturn getResult(rows, -1)\n}\n\nfunc GetResult(rows *sql.Rows) ([]map[string]string, error) {\n\treturn getResult(rows, -1)\n}\n\n// ListResult is a structure for the list result\ntype ListResult struct {\n\tresult []string\n\terr    error\n}\n\n// String return the slice of strings\nfunc (r *ListResult) String() ([]string, error) {\n\tif r.err != nil {\n\t\treturn r.result, r.err\n\t}\n\treturn r.result, nil\n}\n\n// GetList returns the result of the query as ListResult variable\nfunc (dbTx *DbTransaction) GetList(query string, args ...any) *ListResult {\n\tvar result []string\n\tall, err := dbTx.GetAllTransaction(query, -1, args...)\n\tif err != nil {\n\t\treturn &ListResult{result, err}\n\t}\n\tfor _, v := range all {\n\t\tfor _, v2 := range v {\n\t\t\tresult = append(result, v2)\n\t\t}\n\t}\n\treturn &ListResult{result, nil}\n}\n\nfunc getResult(rows *sql.Rows, countRows int) ([]map[string]string, error) {\n\tvar result []map[string]string\n\tdefer rows.Close()\n\t//rows.ColumnTypes()\n\tcolumntypes, err := rows.ColumnTypes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Get column names\n\tcolumns, err := rows.Columns()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Make a slice for the values\n\tvalues := make([][]byte /*sql.RawBytes*/, len(columns))\n\n\t// rows.Scan wants '[]interface{}' as an argument, so we must copy the\n\t// references into such a slice\n\t// See http://code.google.com/p/go-wiki/wiki/InterfaceSlice for details\n\tscanArgs := make([]any, len(values))\n\tfor i := range values {\n\t\tscanArgs[i] = &values[i]\n\t}\n\n\tr := 0\n\t// Fetch rows\n\tfor rows.Next() {\n\t\t// get RawBytes from data\n\t\terr = rows.Scan(scanArgs...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Now do something with the data.\n\t\t// Here we just print each column as a string.\n\t\tvar value string\n\t\trez := make(map[string]string)\n\t\tfor i, col := range values {\n\t\t\t// Here we can check if the value is nil (NULL value)\n\t\t\tif col == nil {\n\t\t\t\tvalue = \"NULL\"\n\t\t\t} else {\n\t\t\t\tif columntypes[i].DatabaseTypeName() == \"BYTEA\" {\n\t\t\t\t\tvalue = hex.EncodeToString(col)\n\t\t\t\t} else {\n\t\t\t\t\tvalue = string(col)\n\t\t\t\t}\n\n\t\t\t}\n\t\t\trez[columns[i]] = value\n\t\t}\n\t\tresult = append(result, rez)\n\t\tr++\n\t\tif countRows != -1 && r >= countRows {\n\t\t\tbreak\n\t\t}\n\t}\n\tif err = rows.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/role.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\n// Role is model\ntype Role struct {\n\tecosystem   int64\n\tID          int64  `gorm:\"primary_key;not null\" json:\"id\"`\n\tDefaultPage string `gorm:\"not null\" json:\"default_page\"`\n\tRoleName    string `gorm:\"not null\" json:\"role_name\"`\n\tDeleted     int64  `gorm:\"not null\" json:\"deleted\"`\n\tRoleType    int64  `gorm:\"not null\" json:\"role_type\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (r *Role) SetTablePrefix(prefix int64) {\n\tr.ecosystem = prefix\n}\n\n// TableName returns name of table\nfunc (r *Role) TableName() string {\n\tif r.ecosystem == 0 {\n\t\tr.ecosystem = 1\n\t}\n\treturn \"1_roles\"\n}\n\n// Get is retrieving model from database\nfunc (r *Role) Get(dbTx *DbTransaction, id int64) (bool, error) {\n\treturn isFound(GetDB(dbTx).First(&r, id))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/roles_participants.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// RolesParticipants represents record of {prefix}roles_participants table\ntype RolesParticipants struct {\n\tecosystem   int64\n\tId          int64\n\tRole        string `gorm:\"type:jsonb\"`\n\tMember      string `gorm:\"type:jsonb\"`\n\tAppointed   string `gorm:\"type:jsonb\"`\n\tDateCreated int64\n\tDateDeleted int64\n\tDeleted     bool\n}\n\n// SetTablePrefix is setting table prefix\nfunc (r *RolesParticipants) SetTablePrefix(prefix int64) *RolesParticipants {\n\tr.ecosystem = prefix\n\treturn r\n}\n\n// TableName returns name of table\nfunc (r RolesParticipants) TableName() string {\n\tif r.ecosystem == 0 {\n\t\tr.ecosystem = 1\n\t}\n\treturn \"1_roles_participants\"\n}\n\n// GetActiveMemberRoles returns active assigned roles for memberID\nfunc (r *RolesParticipants) GetActiveMemberRoles(account string) ([]RolesParticipants, error) {\n\troles := new([]RolesParticipants)\n\terr := DBConn.Table(r.TableName()).Where(\"ecosystem=? and member->>'account' = ? AND deleted = ?\",\n\t\tr.ecosystem, account, 0).Find(&roles).Error\n\treturn *roles, err\n}\n\n// MemberHasRole returns true if member has role\nfunc MemberHasRole(tx *DbTransaction, role, ecosys int64, account string) (bool, error) {\n\tdb := GetDB(tx)\n\tvar count int64\n\tif err := db.Table(\"1_roles_participants\").Where(`ecosystem=? and role->>'id' = ? and member->>'account' = ?`,\n\t\tecosys, converter.Int64ToStr(role), account).Count(&count).Error; err != nil {\n\t\treturn false, err\n\t}\n\n\treturn count > 0, nil\n}\n\n// MemberHasRole returns true if member has role\nfunc MemberHasRolebyName(tx *DbTransaction, ecosys int64, role, account string) (bool, error) {\n\tdb := GetDB(tx)\n\tvar count int64\n\tif err := db.Table(\"1_roles_participants\").Where(`ecosystem=? and role->>'name' = ? and member->>'account' = ?`,\n\t\tecosys, role, account).Count(&count).Error; err != nil {\n\t\treturn false, err\n\t}\n\n\treturn count > 0, nil\n}\n\n// GetMemberRoles return map[id]name all roles assign to member in ecosystem\nfunc GetMemberRoles(tx *DbTransaction, ecosys int64, account string) (roles []int64, err error) {\n\tquery := `SELECT role->>'id' as \"id\" \n\t\tFROM \"1_roles_participants\"\n\t\tWHERE ecosystem = ? and deleted = '0' and member->>'account' = ?`\n\tlist, err := tx.GetAllTransaction(query, -1, ecosys, account)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, role := range list {\n\t\troles = append(roles, converter.StrToInt64(role[`id`]))\n\t}\n\treturn\n}\n\n// GetRoleMembers return []id all members assign to roles in ecosystem\nfunc GetRoleMembers(tx *DbTransaction, ecosys int64, roles []int64) (members []string, err error) {\n\trolesList := make([]string, 0, len(roles))\n\tfor _, role := range roles {\n\t\trolesList = append(rolesList, converter.Int64ToStr(role))\n\t}\n\tquery := `SELECT member->>'account' as \"id\" \n\t\tFROM \"1_roles_participants\" \n\t\tWHERE role->>'id' in (?) group by 1`\n\tlist, err := tx.GetAllTransaction(query, -1, rolesList)\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, member := range list {\n\t\tmembers = append(members, member[`id`])\n\t}\n\treturn\n}\n"
  },
  {
    "path": "packages/storage/sqldb/rollback_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\n\t\"gorm.io/gorm\"\n)\n\n// RollbackTx is model\ntype RollbackTx struct {\n\tID        int64  `gorm:\"primary_key;not null\"`\n\tBlockID   int64  `gorm:\"not null\" json:\"block_id\"`\n\tTxHash    []byte `gorm:\"not null\" json:\"tx_hash\"`\n\tNameTable string `gorm:\"not null;size:255;column:table_name\" json:\"table_name\"`\n\tTableID   string `gorm:\"not null;size:255\" json:\"table_id\"`\n\tData      string `gorm:\"not null;type:jsonb\" json:\"data\"`\n\tDataHash  []byte `gorm:\"not null\" json:\"data_hash\"`\n}\n\n// TableName returns name of table\nfunc (*RollbackTx) TableName() string {\n\treturn \"rollback_tx\"\n}\n\n// GetRollbackTransactions is returns rollback transactions\nfunc (rt *RollbackTx) GetRollbackTransactions(dbTx *DbTransaction, transactionHash []byte) ([]map[string]string, error) {\n\treturn dbTx.GetAllTransaction(\"SELECT * from rollback_tx WHERE tx_hash = ? ORDER BY ID DESC\", -1, transactionHash)\n}\n\n// GetBlockRollbackTransactions returns records of rollback by blockID\nfunc (rt *RollbackTx) GetBlockRollbackTransactions(dbTx *DbTransaction, blockID int64) ([]RollbackTx, error) {\n\tvar rollbackTransactions []RollbackTx\n\terr := GetDB(dbTx).Where(\"block_id = ?\", blockID).Omit(\"id\").Order(\"id asc\").Find(&rollbackTransactions).Error\n\treturn rollbackTransactions, err\n}\n\n// GetRollbackTxsByTableIDAndTableName returns records of rollback by table name and id\nfunc (rt *RollbackTx) GetRollbackTxsByTableIDAndTableName(tableID, tableName string, limit int) (*[]RollbackTx, error) {\n\tvar rollbackTx []RollbackTx\n\tif err := DBConn.Where(\"table_id = ? AND table_name = ?\", tableID, tableName).\n\t\tOrder(\"id desc\").Limit(limit).Find(&rollbackTx).Error; err != nil {\n\t\treturn nil, err\n\t}\n\treturn &rollbackTx, nil\n}\n\n// DeleteByHash is deleting rollbackTx by hash\nfunc (rt *RollbackTx) DeleteByHash(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Exec(\"DELETE FROM rollback_tx WHERE tx_hash = ?\", rt.TxHash).Error\n}\n\n// DeleteByHashAndTableName is deleting tx by hash and table name\nfunc (rt *RollbackTx) DeleteByHashAndTableName(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Where(\"tx_hash = ? and table_name = ?\", rt.TxHash, rt.NameTable).Delete(rt).Error\n}\n\nfunc CreateBatchesRollbackTx(dbTx *gorm.DB, rts []*RollbackTx) error {\n\tif len(rts) == 0 {\n\t\treturn nil\n\t}\n\trollbackSys := &RollbackTx{}\n\tvar err error\n\tif rollbackSys.ID, err = NewDbTransaction(dbTx).GetNextID(rollbackSys.TableName()); err != nil {\n\t\treturn err\n\t}\n\tfor i := 1; i < len(rts)+1; i++ {\n\t\trts[i-1].ID = rollbackSys.ID + int64(i) - 1\n\t}\n\treturn dbTx.Model(&RollbackTx{}).Create(&rts).Error\n}\n\n// Get is retrieving model from database\nfunc (rt *RollbackTx) Get(dbTx *DbTransaction, transactionHash []byte, tableName string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"tx_hash = ? AND table_name = ?\", transactionHash,\n\t\ttableName).Order(\"id desc\").First(rt))\n}\n\nfunc (rt *RollbackTx) GetRollbacksDiff(dbTx *DbTransaction, blockID int64) ([]byte, error) {\n\tlist, err := rt.GetBlockRollbackTransactions(dbTx, blockID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf := new(bytes.Buffer)\n\tenc := json.NewEncoder(buf)\n\tfor _, rtx := range list {\n\t\tif err = enc.Encode(&rtx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn buf.Bytes(), nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/schema.go",
    "content": "package sqldb\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/migration\"\n\t\"github.com/IBAX-io/go-ibax/packages/migration/clb\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// ExecSchemaEcosystem is executing ecosystem schema\nfunc ExecSchemaEcosystem(db *DbTransaction, data migration.SqlData) error {\n\tif data.Ecosystem == 1 {\n\t\tq, err := migration.GetCommonEcosystemScript()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := db.ExecSql(q); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing comma ecosystem schema\")\n\t\t\treturn err\n\t\t}\n\t}\n\tq, err := migration.GetEcosystemScript(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := db.ExecSql(q); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing ecosystem schema\")\n\t\treturn err\n\t}\n\tif data.Ecosystem == 1 {\n\t\tq, err = migration.GetFirstEcosystemScript(data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := db.ExecSql(q); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing first ecosystem schema\")\n\t\t}\n\t\tq, err = migration.GetFirstTableScript(data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := db.ExecSql(q); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing first tables schema\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc ExecSubSchema() error {\n\tif conf.Config.IsSubNode() {\n\t\tif err := migration.InitMigrate(&MigrationHistory{}); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on executing clb script\")\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ExecCLBSchema is executing schema for off blockchainService\nfunc ExecCLBSchema(id int, wallet int64) error {\n\n\tif conf.Config.IsSupportingCLB() {\n\t\tif err := migration.InitMigrate(&MigrationHistory{}); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on executing clb script\")\n\t\t\treturn err\n\t\t}\n\n\t\tquery := fmt.Sprintf(clb.GetCLBScript(), id, wallet, converter.AddressToString(wallet))\n\t\tif err := DBConn.Exec(query).Error; err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"on executing clb script\")\n\t\t\treturn err\n\t\t}\n\n\t\tpubfunc := func(privateKeyFilename string) ([]byte, error) {\n\t\t\tvar (\n\t\t\t\tprivkey, privKey, pubKey []byte\n\t\t\t\terr                      error\n\t\t\t)\n\t\t\tprivkey, err = os.ReadFile(filepath.Join(conf.Config.DirPathConf.KeysDir, privateKeyFilename))\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading private key from file\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tprivKey, err = hex.DecodeString(string(privkey))\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"decoding private key from hex\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tpubKey, err = crypto.PrivateToPublic(privKey)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"converting private key to public\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn pubKey, nil\n\t\t}\n\n\t\tnodePubKey, err := pubfunc(consts.NodePrivateKeyFilename)\n\t\tPubKey, err := pubfunc(consts.PrivateKeyFilename)\n\t\tnodeKeyID := crypto.Address(nodePubKey)\n\t\tkeyID := crypto.Address(PubKey)\n\t\tamount := decimal.New(consts.FounderAmount, int32(consts.MoneyDigits)).String()\n\t\tif err = GetDB(nil).Exec(`insert into \"1_keys\" (account,pub,amount) values (?,?,?,?),(?,?,?,?)`,\n\t\t\tkeyID, converter.AddressToString(keyID), PubKey, amount, nodeKeyID, converter.AddressToString(nodeKeyID), nodePubKey, 0).Error; err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// ExecSchema is executing schema\nfunc ExecSchema() error {\n\treturn migration.InitMigrate(&MigrationHistory{})\n}\n\n// UpdateSchema run update migrations\nfunc UpdateSchema() error {\n\tif !conf.Config.IsCLBMaster() {\n\t\tb := &BlockChain{}\n\t\tif found, err := b.GetMaxBlock(); !found {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn migration.UpdateMigrate(&MigrationHistory{})\n}\n"
  },
  {
    "path": "packages/storage/sqldb/send_tx.go",
    "content": "package sqldb\n\nimport (\n\t\"gorm.io/gorm\"\n\n\t\"gorm.io/gorm/clause\"\n\n\t\"github.com/shopspring/decimal\"\n)\n\n// SendTx is creates transaction\n//func SendTx(rtx types.TransactionInfoer, adminWallet int64) error {\n//\tts := &TransactionStatus{\n//\t\tHash:     rtx.TxHashes(),\n//\t\tTime:     rtx.Time(),\n//\t\tType:     rtx.Type(),\n//\t\tWalletID: adminWallet,\n//\t}\n//\tfoundts, err := ts.Get(rtx.TxHashes())\n//\tif foundts {\n//\t\tlog.WithFields(log.Fields{\"tx_hash\": rtx.TxHashes(), \"wallet_id\": adminWallet, \"tx_time\": ts.Time, \"type\": consts.DuplicateObject}).Error(\"double tx in transactions status\")\n//\t\treturn errors.New(\"duplicated transaction from transactions status\")\n//\t}\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting transaction from transactions status\")\n//\t\treturn err\n//\t}\n//\terr = ts.Create()\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"transaction status create\")\n//\t\treturn err\n//\t}\n//\n//\tqtx := &QueueTx{\n//\t\tHash:     rtx.TxHashes(),\n//\t\tData:     rtx.Bytes(),\n//\t\tExpedite: rtx.GetExpedite(),\n//\t\tTime:     rtx.Time(),\n//\t}\n//\tfoundqx, err := qtx.GetByHash(nil, rtx.TxHashes())\n//\tif foundqx {\n//\t\tlog.WithFields(log.Fields{\"tx_hash\": rtx.TxHashes(), \"wallet_id\": adminWallet, \"tx_time\": ts.Time, \"type\": consts.DuplicateObject}).Error(\"double tx in queue tx\")\n//\t\treturn errors.New(\"duplicated transaction from queue tx \")\n//\t}\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting transaction from queue tx\")\n//\t\treturn err\n//\t}\n//\treturn qtx.Create()\n//}\n\ntype RawTx struct {\n\tTxType   byte\n\tTime     int64\n\tHash     []byte\n\tData     []byte\n\tExpedite string\n\tWalletID int64\n}\n\nfunc (rtx *RawTx) GetExpedite() decimal.Decimal {\n\texpedite, _ := decimal.NewFromString(rtx.Expedite)\n\treturn expedite\n}\n\nfunc SendTxBatches(rtxs []*RawTx) error {\n\tvar rawTxs []*TransactionStatus\n\tvar qtxs []*QueueTx\n\tfor _, rtx := range rtxs {\n\t\tts := &TransactionStatus{\n\t\t\tHash:     rtx.Hash,\n\t\t\tTime:     rtx.Time,\n\t\t\tType:     rtx.TxType,\n\t\t\tWalletID: rtx.WalletID,\n\t\t}\n\t\trawTxs = append(rawTxs, ts)\n\t\tqtx := &QueueTx{\n\t\t\tHash:     rtx.Hash,\n\t\t\tData:     rtx.Data,\n\t\t\tExpedite: rtx.GetExpedite(),\n\t\t\tTime:     rtx.Time,\n\t\t}\n\t\tqtxs = append(qtxs, qtx)\n\t}\n\treturn DBConn.Clauses(clause.OnConflict{DoNothing: true}).Transaction(func(tx *gorm.DB) error {\n\t\tif err := tx.Create(&rawTxs).Error; err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := tx.Create(&qtxs).Error; err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n\n}\n"
  },
  {
    "path": "packages/storage/sqldb/signatures.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\n// Signature is model\ntype Signature struct {\n\ttableName  string\n\tName       string `gorm:\"primary_key;not null;size:255\"`\n\tValue      string `gorm:\"not null;type:jsonb\"`\n\tConditions string `gorm:\"not null\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (s *Signature) SetTablePrefix(prefix string) {\n\ts.tableName = prefix + \"_signatures\"\n}\n\n// TableName returns name of table\nfunc (s *Signature) TableName() string {\n\treturn s.tableName\n}\n\n// Get is retrieving model from database\nfunc (s *Signature) Get(name string) (bool, error) {\n\treturn isFound(DBConn.Where(\"name = ?\", name).First(s))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/snippet.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport \"github.com/IBAX-io/go-ibax/packages/converter\"\n\n// Snippet is code snippet\ntype Snippet struct {\n\tecosystem  int64\n\tID         int64  `gorm:\"primary_key;not null\" json:\"id,omitempty\"`\n\tName       string `gorm:\"not null\" json:\"name,omitempty\"`\n\tValue      string `gorm:\"not null\" json:\"value,omitempty\"`\n\tConditions string `gorm:\"not null\" json:\"conditions,omitempty\"`\n}\n\n// SetTablePrefix is setting table prefix\nfunc (bi *Snippet) SetTablePrefix(prefix string) {\n\tbi.ecosystem = converter.StrToInt64(prefix)\n}\n\n// TableName returns name of table\nfunc (bi *Snippet) TableName() string {\n\tif bi.ecosystem == 0 {\n\t\tbi.ecosystem = 1\n\t}\n\treturn `1_snippets`\n}\n\n// Get is retrieving model from database\nfunc (bi *Snippet) Get(name string) (bool, error) {\n\treturn isFound(DBConn.Where(\"ecosystem=? and name = ?\", bi.ecosystem, name).First(bi))\n}\n\n// GetByApp returns all interface blocks belonging to selected app\nfunc (bi *Snippet) GetByApp(appID int64, ecosystemID int64) ([]Snippet, error) {\n\tvar result []Snippet\n\terr := DBConn.Select(\"id, name\").Where(\"app_id = ? and ecosystem = ?\", appID, ecosystemID).Find(&result).Error\n\treturn result, err\n}\n"
  },
  {
    "path": "packages/storage/sqldb/spent_info.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"gorm.io/gorm\"\n\t\"gorm.io/gorm/clause\"\n)\n\n// SpentInfo is model\ntype SpentInfo struct {\n\tInputTxHash  []byte `gorm:\"default:(-)\"`\n\tInputIndex   int32\n\tOutputTxHash []byte `gorm:\"not null\"`\n\tOutputIndex  int32  `gorm:\"not null\"`\n\tOutputKeyId  int64  `gorm:\"not null\"`\n\tOutputValue  string `gorm:\"not null\"`\n\tEcosystem    int64\n\tBlockId      int64\n\tType         int32\n}\n\ntype KeyUTXO struct {\n\tEcosystem int64\n\t//At        string\n\tKeyId int64\n\t// Asset        string\n}\n\nfunc (k *KeyUTXO) String() string {\n\treturn fmt.Sprintf(\"%d%s%d\", k.Ecosystem, \"@\", k.KeyId)\n}\n\n// TableName returns name of table\nfunc (si *SpentInfo) TableName() string {\n\treturn \"spent_info\"\n}\n\n// CreateSpentInfoBatches is creating record of model\nfunc CreateSpentInfoBatches(dbTx *gorm.DB, spentInfos []SpentInfo) error {\n\t//for _, info := range spentInfos {\n\t//\tfmt.Println(hex.EncodeToString(info.InputTxHash), info.InputIndex, hex.EncodeToString(info.OutputTxHash), info.OutputIndex, info.OutputKeyId, info.OutputValue, info.BlockId)\n\t//}\n\n\treturn dbTx.Clauses(clause.OnConflict{\n\t\tColumns:   []clause.Column{{Name: \"output_tx_hash\"}, {Name: \"output_key_id\"}, {Name: \"output_index\"}},\n\t\tDoUpdates: clause.AssignmentColumns([]string{\"input_tx_hash\", \"input_index\"}),\n\t\tWhere: clause.Where{Exprs: []clause.Expression{\n\t\t\tclause.Eq{Column: \"spent_info.output_tx_hash\", Value: gorm.Expr(`\"excluded\".\"output_tx_hash\"`)},\n\t\t\tclause.Eq{Column: \"spent_info.output_key_id\", Value: gorm.Expr(`\"excluded\".\"output_key_id\"`)},\n\t\t\tclause.Eq{Column: \"spent_info.output_index\", Value: gorm.Expr(`\"excluded\".\"output_index\"`)},\n\t\t}},\n\t}).CreateInBatches(spentInfos, 1000).Error\n}\n\nfunc GetTxOutputsEcosystem(db *DbTransaction, ecosystem int64, keyIds []int64) ([]SpentInfo, error) {\n\tquery :=\n\t\t` SELECT si.output_tx_hash, si.output_index, si.output_key_id, si.output_value, si.ecosystem, si.block_id\n\t\tFROM spent_info si LEFT JOIN log_transactions AS tr ON si.output_tx_hash = tr.hash\n\t\tWHERE si.ecosystem = ? AND si.output_key_id IN ? AND  si.input_tx_hash IS NULL\n\t\tORDER BY si.output_key_id, si.block_id ASC, tr.timestamp ASC `\n\tvar result []SpentInfo\n\terr := GetDB(db).Raw(query, ecosystem, keyIds).Scan(&result).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc GetTxOutputs(db *DbTransaction, keyIds []int64) ([]SpentInfo, error) {\n\tquery :=\n\t\t` SELECT si.output_tx_hash, si.output_index, si.output_key_id, si.output_value, si.ecosystem, si.block_id\n\t\tFROM spent_info si LEFT JOIN log_transactions AS tr ON si.output_tx_hash = tr.hash\n\t\tWHERE si.output_key_id IN ? AND si.input_tx_hash IS NULL\n\t\tORDER BY si.output_key_id, si.block_id ASC, tr.timestamp ASC `\n\tvar result []SpentInfo\n\terr := GetDB(db).Raw(query, keyIds).Scan(&result).Error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc RollbackOutputs(blockID int64, db *DbTransaction, transferSelfHashes []string, logger *log.Entry) error {\n\terr := GetDB(db).Exec(`UPDATE spent_info SET  input_tx_hash= null , input_index=0 WHERE input_tx_hash  in ( SELECT output_tx_hash FROM \"spent_info\"  WHERE block_id = ? )`, blockID).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Errorf(\"updating input_tx_hash rollback outputs by blockID : %d\", blockID)\n\t\treturn err\n\t}\n\tif len(transferSelfHashes) > 0 {\n\t\terr = GetDB(db).Exec(`UPDATE spent_info SET  input_tx_hash= null , input_index=0 WHERE encode(input_tx_hash,'hex') in ?`, transferSelfHashes).Error\n\t\tif err != nil {\n\t\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Errorf(\"updating input_tx_hash of transfer self for rollback outputs by blockID : %d\", blockID)\n\t\t\treturn err\n\t\t}\n\t}\n\n\terr = GetDB(db).Exec(`DELETE FROM spent_info WHERE block_id = ? `, blockID).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Errorf(\"deleting rollback outputs by blockID : %d\", blockID)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc GetBlockOutputs(dbTx *DbTransaction, blockID int64) ([]SpentInfo, error) {\n\tvar result []SpentInfo\n\terr := GetDB(dbTx).Where(\"block_id = ?\", blockID).Find(&result).Error\n\treturn result, err\n}\n\nfunc (si *SpentInfo) GetBalance(db *DbTransaction, keyId, ecosystem int64) (decimal.Decimal, error) {\n\tvar amount decimal.Decimal\n\tf, err := isFound(GetDB(db).Table(si.TableName()).Select(\"coalesce(sum(output_value),'0') amount\").\n\t\tWhere(\"input_tx_hash is NULL AND output_key_id = ? AND ecosystem = ?\", keyId, ecosystem).Take(&amount))\n\tif err != nil {\n\t\treturn decimal.Zero, err\n\t}\n\tif !f {\n\t\treturn decimal.Zero, errors.New(\"doesn't not exist UTXO output_key_id\")\n\t}\n\n\treturn amount, err\n}\n\n// GetTopAmounts returns top amounts by ecosystem, rank and dense\nfunc GetTopAmounts(db *DbTransaction, ecosystem int64, rank int64, dense bool) ([]any, error) {\n\tquery := `\nSELECT * FROM \n    (SELECT sum ( amount ) AS amount,\n     id,\n     CASE \n    \tWHEN ? THEN dense_rank() OVER (ORDER BY sum ( amount )  DESC)\n    \tELSE rank() OVER (ORDER BY sum ( amount )  DESC)\n  \tEND AS rank\n    FROM \n        (SELECT output_value AS amount,\n     output_key_id AS id\n        FROM spent_info\n        LEFT JOIN \"1_keys\"\n          ON spent_info.ecosystem = \"1_keys\".ecosystem\n            AND id = spent_info.output_key_id\n        WHERE input_tx_hash is null\n            AND \"spent_info\".ecosystem = ?\n            AND blocked = 0\n            AND deleted = 0\n            AND length ( pub ) > 0\nUNION\nSELECT amount, id  FROM \"1_keys\"\n        WHERE ecosystem = ?\n            AND blocked = 0\n            AND deleted = 0\n            AND amount > 0\n            AND length ( pub ) > 0 ) tmp\n        GROUP BY  id\n        ORDER BY  rank ASC ) r\n    WHERE rank <= ?\nORDER BY  rank, id;\n`\n\trows, err := GetDB(db).Raw(query, dense, ecosystem, ecosystem, rank).Rows()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer rows.Close()\n\tcols, err := rows.Columns()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: %s\", err, \"getting rows columns\")\n\t}\n\tvalues := make([][]byte, len(cols))\n\tscanArgs := make([]any, len(values))\n\tfor i := range values {\n\t\tscanArgs[i] = &values[i]\n\t}\n\n\tresult := make([]any, 0)\n\tfor rows.Next() {\n\t\terr = rows.Scan(scanArgs...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s\", err, \"scanning next row\")\n\t\t}\n\t\trow := types.NewMap()\n\t\tfor i, col := range values {\n\t\t\tvar value string\n\t\t\tif col != nil {\n\t\t\t\tvalue = string(col)\n\t\t\t}\n\t\t\trow.Set(cols[i], value)\n\t\t}\n\t\tresult = append(result, reflect.ValueOf(row).Interface())\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "packages/storage/sqldb/stop_daemons.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"time\"\n)\n\n// StopDaemon is model\ntype StopDaemon struct {\n\tStopTime int64 `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (sd *StopDaemon) TableName() string {\n\treturn \"stop_daemons\"\n}\n\n// Create is creating record of model\nfunc (sd *StopDaemon) Create() error {\n\treturn DBConn.Create(sd).Error\n}\n\n// Delete is deleting record\nfunc (sd *StopDaemon) Delete() error {\n\treturn DBConn.Delete(&StopDaemon{}).Error\n}\n\n// Get is retrieving model from database\nfunc (sd *StopDaemon) Get() (bool, error) {\n\treturn isFound(DBConn.First(sd))\n}\n\n// SetStopNow is updating daemon stopping time to now\nfunc SetStopNow() error {\n\tstopTime := &StopDaemon{StopTime: time.Now().Unix()}\n\treturn stopTime.Create()\n}\n"
  },
  {
    "path": "packages/storage/sqldb/tables.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"database/sql/driver\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\t\"gorm.io/gorm\"\n)\n\n// const TableName = \"1_tables\"\n\n// Table is model\ntype Table struct {\n\tID          int64       `gorm:\"primary_key;not null\"`\n\tName        string      `gorm:\"not null;size:100\"`\n\tPermissions Permissions `gorm:\"not null;type:jsonb\"`\n\tColumns     string      `gorm:\"not null\"`\n\tConditions  string      `gorm:\"not null\"`\n\tAppID       int64       `gorm:\"not null\"`\n\tEcosystem   int64       `gorm:\"not null\"`\n}\n\ntype Permissions struct {\n\tInsert    string `json:\"insert\"`\n\tNewColumn string `json:\"new_column\"`\n\tUpdate    string `json:\"update\"`\n\tRead      string `json:\"read\"`\n\tFilter    string `json:\"filter\"`\n}\n\nfunc (p Permissions) Value() (driver.Value, error) {\n\tdata, err := json.Marshal(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn string(data), err\n}\nfunc (p *Permissions) Scan(v any) error {\n\tdata, ok := v.([]byte)\n\tif !ok {\n\t\treturn errors.New(\"Bad permissions\")\n\t}\n\treturn json.Unmarshal(data, p)\n}\n\n// SetTablePrefix is setting table prefix\nfunc (t *Table) SetTablePrefix(prefix string) {\n\tt.Ecosystem = converter.StrToInt64(prefix)\n}\n\n// TableName returns name of table\nfunc (t *Table) TableName() string {\n\tif t.Ecosystem == 0 {\n\t\tt.Ecosystem = 1\n\t}\n\treturn `1_tables`\n}\n\n// Get is retrieving model from database\nfunc (t *Table) Get(dbTx *DbTransaction, name string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"ecosystem = ? and name = ?\", t.Ecosystem, name).First(t))\n}\n\n// Create is creating record of model\nfunc (t *Table) Create(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Create(t).Error\n}\n\n// Delete is deleting model from database\nfunc (t *Table) Delete(dbTx *DbTransaction) error {\n\treturn GetDB(dbTx).Delete(t).Error\n}\n\n// IsExistsByPermissionsAndTableName returns columns existence by permission and table name\nfunc (t *Table) IsExistsByPermissionsAndTableName(dbTx *DbTransaction, columnName, tableName string) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(`ecosystem = ? AND (columns-> ? ) is not null AND name = ?`,\n\t\tt.Ecosystem, columnName, tableName).First(t))\n}\n\n// GetColumns returns columns from database\nfunc (t *Table) GetColumns(dbTx *DbTransaction, name, jsonKey string) (map[string]string, error) {\n\tkeyStr := \"\"\n\tif jsonKey != \"\" {\n\t\tkeyStr = `->'` + jsonKey + `'`\n\t}\n\trows, err := GetDB(dbTx).Raw(`SELECT data.* FROM \"1_tables\", jsonb_each_text(columns`+keyStr+`) AS data WHERE ecosystem = ? AND name = ?`, t.Ecosystem, name).Rows()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer rows.Close()\n\tvar key, value string\n\tresult := map[string]string{}\n\tfor rows.Next() {\n\t\trows.Scan(&key, &value)\n\t\tresult[key] = value\n\t}\n\terr = rows.Err()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\n// GetPermissions returns table permissions by name\nfunc (t *Table) GetPermissions(dbTx *DbTransaction, name, jsonKey string) (map[string]string, error) {\n\tkeyStr := \"\"\n\tif jsonKey != \"\" {\n\t\tkeyStr = `->'` + jsonKey + `'`\n\t}\n\trows, err := GetDB(dbTx).Raw(`SELECT data.* FROM \"1_tables\", jsonb_each_text(permissions`+keyStr+`) AS data WHERE ecosystem = ? AND name = ?`, t.Ecosystem, name).Rows()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer rows.Close()\n\tvar key, value string\n\tresult := map[string]string{}\n\tfor rows.Next() {\n\t\trows.Scan(&key, &value)\n\t\tresult[key] = value\n\t}\n\terr = rows.Err()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc (t *Table) Count() (count int64, err error) {\n\terr = GetDB(nil).Table(t.TableName()).Where(\"ecosystem= ?\", t.Ecosystem).Count(&count).Error\n\treturn\n}\n\n// CreateTable is creating table\nfunc CreateTable(dbTx *DbTransaction, tableName, colsSQL string) error {\n\treturn dbTx.ExecSql(`CREATE TABLE \"` + tableName + `\" (\n\t\t\t\t\"id\" bigint NOT NULL DEFAULT '0',\n\t\t\t\t` + colsSQL + `\n\t\t\t\t);\n\t\t\t\tALTER TABLE ONLY \"` + tableName + `\" ADD CONSTRAINT \"` + tableName + `_pkey\" PRIMARY KEY (id);`)\n}\n\n// CreateView is creating view table\nfunc CreateView(dbTx *DbTransaction, inViewName, inTables, inWhere, inColSQL string) error {\n\tinSQL := `CREATE VIEW \"` + inViewName + `\" AS SELECT ` + inColSQL + ` FROM ` + inTables + ` WHERE ` + inWhere + `;`\n\treturn dbTx.ExecSql(inSQL)\n}\n\n// DropView is drop view table\nfunc DropView(dbTx *DbTransaction, inViewName string) error {\n\treturn dbTx.ExecSql(`DROP VIEW \"` + strings.Replace(fmt.Sprint(inViewName), `'`, `''`, -1) + `\";`)\n}\n\n// GetAll returns all tables\nfunc (t *Table) GetAll(prefix string) ([]Table, error) {\n\tresult := make([]Table, 0)\n\terr := DBConn.Table(\"1_tables\").Where(\"ecosystem = ?\", prefix).Find(&result).Error\n\treturn result, err\n}\n\n// func (t *Table) GetList(offset, limit int) ([]Table, error) {\n// \tvar list []Table\n// \terr := DBConn.Table(t.TableName()).Offset(offset).Limit(limit).Select(\"name\").Order(\"name\").Find(&list).Error\n// \treturn list, err\n// }\n\n// GetRowConditionsByTableNameAndID returns value of `conditions` field for table row by id\nfunc (dbTx *DbTransaction) GetRowConditionsByTableNameAndID(tblname string, id int64) (string, error) {\n\tsql := `SELECT conditions FROM \"` + tblname + `\" WHERE id = ? LIMIT 1`\n\treturn dbTx.Single(sql, id).String()\n}\n\nfunc GetTableQuery(table string, ecosystemID int64) *gorm.DB {\n\tif converter.FirstEcosystemTables[table] {\n\t\treturn GetDB(nil).Table(\"1_\"+table).Where(\"ecosystem = ?\", ecosystemID)\n\t}\n\n\treturn GetDB(nil).Table(converter.ParseTable(table, ecosystemID))\n}\n\nfunc GetTableListQuery(table string, ecosystemID int64) *gorm.DB {\n\tif converter.FirstEcosystemTables[table] {\n\t\treturn DBConn.Table(\"1_\" + table)\n\t}\n\n\treturn GetDB(nil).Table(converter.ParseTable(table, ecosystemID))\n}\n"
  },
  {
    "path": "packages/storage/sqldb/transaction.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/shopspring/decimal\"\n\t\"gorm.io/gorm\"\n\t\"gorm.io/gorm/clause\"\n)\n\n// This constants contains values of transactions priority\nconst (\n\tTransactionRateOnBlock transactionRate = iota + 1\n\tTransactionRateApiContract\n\tTransactionRateStopNetwork\n)\nconst expediteOrder = `high_rate,expedite DESC,time ASC`\n\ntype transactionRate int8\n\n// Transaction is model\ntype Transaction struct {\n\tHash     []byte          `gorm:\"private_key;not null\"`\n\tData     []byte          `gorm:\"not null\"`\n\tUsed     int8            `gorm:\"not null\"`\n\tHighRate transactionRate `gorm:\"not null\"`\n\tExpedite decimal.Decimal `gorm:\"not null\"`\n\tType     int8            `gorm:\"not null\"`\n\tKeyID    int64           `gorm:\"not null\"`\n\tSent     int8            `gorm:\"not null\"`\n\tVerified int8            `gorm:\"not null\"`\n\tTime     int64           `gorm:\"not null\"`\n}\n\n// GetAllUnusedTransactions is retrieving all unused transactions\nfunc GetAllUnusedTransactions(dbTx *DbTransaction, limit int) ([]*Transaction, error) {\n\tvar transactions []*Transaction\n\n\tquery := GetDB(dbTx).Where(\"used = ?\", \"0\").Order(expediteOrder)\n\tif limit > 0 {\n\t\tquery = query.Limit(limit)\n\t}\n\n\tif err := query.Find(&transactions).Error; err != nil {\n\t\treturn nil, err\n\t}\n\treturn transactions, nil\n}\n\n// GetAllUnsentTransactions is retrieving all unset transactions\nfunc GetAllUnsentTransactions(limit int) (*[]Transaction, error) {\n\ttransactions := new([]Transaction)\n\tquery := DBConn.Where(\"sent = ?\", \"0\").Order(expediteOrder)\n\tif limit > 0 {\n\t\tquery = query.Limit(limit)\n\t}\n\tif err := query.Find(&transactions).Error; err != nil {\n\t\treturn nil, err\n\t}\n\treturn transactions, nil\n}\n\n// GetTransactionCountAll count all transactions\nfunc GetTransactionCountAll() (int64, error) {\n\tvar rowsCount int64\n\tif err := DBConn.Table(\"transactions\").Count(&rowsCount).Error; err != nil {\n\t\treturn -1, err\n\t}\n\treturn rowsCount, nil\n}\n\n// GetTransactionsCount count all transactions by hash\nfunc GetTransactionsCount(hash []byte) (int64, error) {\n\tvar rowsCount int64\n\tif err := DBConn.Table(\"transactions\").Where(\"hash = ?\", hash).Count(&rowsCount).Error; err != nil {\n\t\treturn -1, err\n\t}\n\treturn rowsCount, nil\n}\n\n// DeleteTransactionByHash deleting transaction by hash\nfunc DeleteTransactionByHash(dbTx *DbTransaction, hash []byte) error {\n\treturn GetDB(dbTx).Where(\"hash = ?\", hash).Delete(&Transaction{}).Error\n}\n\n// DeleteUsedTransactions deleting used transaction\nfunc DeleteUsedTransactions(dbTx *DbTransaction) (int64, error) {\n\tquery := GetDB(dbTx).Exec(\"DELETE FROM transactions WHERE used = 1\")\n\treturn query.RowsAffected, query.Error\n}\n\n// DeleteTransactionIfUnused deleting unused transaction\nfunc DeleteTransactionIfUnused(dbTx *DbTransaction, transactionHash []byte) (int64, error) {\n\tquery := GetDB(dbTx).Exec(\"DELETE FROM transactions WHERE hash = ? and used = 0 and verified = 0\", transactionHash)\n\treturn query.RowsAffected, query.Error\n}\n\n// MarkTransactionSent is marking transaction as sent\nfunc MarkTransactionSent(transactionHash []byte) (int64, error) {\n\tquery := DBConn.Exec(\"UPDATE transactions SET sent = 1 WHERE hash = ?\", transactionHash)\n\treturn query.RowsAffected, query.Error\n}\n\n// MarkTransactionSentBatches is marking transaction as sent\nfunc MarkTransactionSentBatches(hashArr [][]byte) error {\n\treturn DBConn.Exec(\"UPDATE transactions SET sent  = 1 WHERE hash in(?)\", hashArr).Error\n}\n\n// MarkTransactionUsed is marking transaction as used\nfunc MarkTransactionUsed(dbTx *DbTransaction, transactionHash []byte) (int64, error) {\n\tquery := GetDB(dbTx).Exec(\"UPDATE transactions SET used = 1 WHERE hash = ?\", transactionHash)\n\treturn query.RowsAffected, query.Error\n}\n\n// MarkTransactionUnusedAndUnverified is marking transaction unused and unverified\nfunc MarkTransactionUnusedAndUnverified(dbTx *DbTransaction, transactionHash []byte) (int64, error) {\n\tquery := GetDB(dbTx).Exec(\"UPDATE transactions SET used = 0, verified = 0 WHERE hash = ?\", transactionHash)\n\treturn query.RowsAffected, query.Error\n}\n\n// MarkVerifiedAndNotUsedTransactionsUnverified is marking verified and unused transaction as unverified\nfunc MarkVerifiedAndNotUsedTransactionsUnverified() (int64, error) {\n\tquery := DBConn.Exec(\"UPDATE transactions SET verified = 0 WHERE verified = 1 AND used = 0\")\n\treturn query.RowsAffected, query.Error\n}\n\n// Read is checking transaction existence by hash\nfunc (t *Transaction) Read(hash []byte) (bool, error) {\n\treturn isFound(DBConn.Where(\"hash = ?\", hash).First(t))\n}\n\n// Get is retrieving model from database\nfunc (t *Transaction) Get(transactionHash []byte) (bool, error) {\n\treturn isFound(DBConn.Where(\"hash = ?\", transactionHash).First(t))\n}\n\n// GetVerified is checking transaction verification by hash\nfunc (t *Transaction) GetVerified(transactionHash []byte) (bool, error) {\n\treturn isFound(DBConn.Where(\"hash = ? AND verified = 1\", transactionHash).First(t))\n}\n\nfunc (t *Transaction) BeforeCreate(db *gorm.DB) error {\n\tif t.HighRate == 0 {\n\t\tt.HighRate = GetTxRateByTxType(t.Type)\n\t}\n\treturn nil\n}\n\n// Create is creating record of model\nfunc (t *Transaction) Create(db *DbTransaction) error {\n\treturn GetDB(db).Create(&t).Error\n}\n\n// CreateTransactionBatches is creating record of model\nfunc CreateTransactionBatches(db *DbTransaction, trs []*Transaction) error {\n\treturn GetDB(db).Clauses(clause.OnConflict{DoNothing: true}).Create(&trs).Error\n}\n\nfunc (t *Transaction) BeforeUpdate(db *gorm.DB) error {\n\treturn db.Where(\"hash = ?\", t.Hash).FirstOrCreate(&t).Error\n}\n\nfunc (t *Transaction) Update(db *DbTransaction) error {\n\treturn GetDB(db).Where(\"hash = ?\", t.Hash).Updates(&t).Error\n}\n\nfunc GetTxRateByTxType(txType int8) transactionRate {\n\tswitch txType {\n\tcase types.StopNetworkTxType:\n\t\treturn TransactionRateStopNetwork\n\tdefault:\n\t\treturn TransactionRateApiContract\n\t}\n}\n\nfunc GetManyTransactions(dbtx *DbTransaction, hashes [][]byte) ([]Transaction, error) {\n\ttxes := []Transaction{}\n\tquery := GetDB(dbtx).Where(\"hash in (?)\", hashes).Find(&txes)\n\tif err := query.Error; err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn txes, nil\n}\n\nfunc (t *Transaction) GetStopNetwork() (bool, error) {\n\treturn isFound(DBConn.Where(\"type = ?\", types.StopNetworkTxType).First(t))\n}\n\nfunc (t *Transaction) GetTransactionRateStopNetwork() bool {\n\treturn t.HighRate == TransactionRateStopNetwork\n}\n\nfunc DeleteTransactions(dbTx *gorm.DB, hs [][]byte) error {\n\tif len(hs) == 0 {\n\t\treturn nil\n\t}\n\treturn dbTx.Delete(&Transaction{}, hs).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/transaction_status.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"gorm.io/gorm\"\n)\n\n// TransactionStatus is model\ntype TransactionStatus struct {\n\tHash     []byte `gorm:\"primary_key;not null\"`\n\tTime     int64  `gorm:\"not null;\"`\n\tType     byte   `gorm:\"not null\"`\n\tWalletID int64  `gorm:\"not null\"`\n\tBlockID  int64  `gorm:\"not null\"`\n\tError    string `gorm:\"not null\"`\n\tPenalty  int64  `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (ts *TransactionStatus) TableName() string {\n\treturn \"transactions_status\"\n}\n\n// Create is creating record of model\nfunc (ts *TransactionStatus) Create() error {\n\treturn DBConn.Create(ts).Error\n}\n\n// Get is retrieving model from database\nfunc (ts *TransactionStatus) Get(transactionHash []byte) (bool, error) {\n\treturn isFound(DBConn.Where(\"hash = ?\", transactionHash).First(ts))\n}\n\n// UpdateBlockID is updating block id\nfunc (ts *TransactionStatus) UpdateBlockID(dbTx *DbTransaction, newBlockID int64, transactionHash []byte) error {\n\treturn GetDB(dbTx).Model(&TransactionStatus{}).Where(\"hash = ?\", transactionHash).Update(\"block_id\", newBlockID).Error\n}\n\nfunc UpdateBlockMsgBatches(dbTx *gorm.DB, newBlockID int64, updBlockMsg []*pbgo.TxResult) error {\n\tif len(updBlockMsg) == 0 {\n\t\treturn nil\n\t}\n\tvar (\n\t\tupErrStr, upBlockIdStr string\n\t\thashArr                []string\n\t\theader                 = \"UPDATE transactions_status SET\"\n\t\tcolErr, colBlockId     = \"error = CASE hash\", \"block_id = CASE hash\"\n\t)\n\n\tfor _, s := range updBlockMsg {\n\t\tif s == nil {\n\t\t\tcontinue\n\t\t}\n\t\thashArr = append(hashArr, fmt.Sprintf(\"decode('%x','hex')\", s.Hash))\n\t\tupErrStr += fmt.Sprintf(\"WHEN decode('%x','hex') THEN '%s' \", s.Hash, strings.Replace(s.Result, `'`, `''`, -1))\n\t\tupBlockIdStr += fmt.Sprintf(\"WHEN decode('%x','hex') THEN %d \", s.Hash, newBlockID)\n\t}\n\tif len(hashArr) == 0 {\n\t\treturn nil\n\t}\n\tsqlStr := fmt.Sprintf(\"%s \", header)\n\tsqlStr += fmt.Sprintf(\" %s %s END,\", colErr, upErrStr)\n\tsqlStr += fmt.Sprintf(\" %s %s END\", colBlockId, upBlockIdStr)\n\tsqlStr += fmt.Sprintf(\" WHERE hash in(%s)\", strings.Join(hashArr, \",\"))\n\treturn dbTx.Exec(sqlStr).Error\n}\n\n// SetError is updating transaction status error\nfunc (ts *TransactionStatus) SetError(dbTx *DbTransaction, errorText string, transactionHash []byte) error {\n\treturn GetDB(dbTx).Model(&TransactionStatus{}).Where(\"hash = ?\", transactionHash).Update(\"error\", errorText).Error\n}\n\n// UpdatePenalty is updating penalty\nfunc (ts *TransactionStatus) UpdatePenalty(dbTx *DbTransaction, transactionHash []byte) error {\n\treturn GetDB(dbTx).Model(&TransactionStatus{}).Where(\"hash = ? AND penalty = 0\", transactionHash).Update(\"penalty\", int64(pbgo.TxInvokeStatusCode_PENALTY)).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/transactions_attempts.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\n// TransactionsAttempts is model\ntype TransactionsAttempts struct {\n\tHash    []byte `gorm:\"primary_key;not null\"`\n\tAttempt int8   `gorm:\"not null\"`\n}\n\n// TableName returns name of table\nfunc (m TransactionsAttempts) TableName() string {\n\treturn `transactions_attempts`\n}\n\n// GetByHash returns TransactionsAttempts existence by hash\nfunc (ta *TransactionsAttempts) GetByHash(dbTx *DbTransaction, hash []byte) (bool, error) {\n\treturn isFound(GetDB(dbTx).Where(\"hash = ?\", hash).First(&ta))\n}\n\n// IncrementTxAttemptCount increases attempt column\nfunc IncrementTxAttemptCount(dbTx *DbTransaction, transactionHash []byte) (int64, error) {\n\tta := &TransactionsAttempts{}\n\tfound, err := ta.GetByHash(dbTx, transactionHash)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tif found {\n\t\tif ta.Attempt > 125 {\n\t\t\treturn int64(ta.Attempt), nil\n\t\t}\n\t\terr = GetDB(dbTx).Exec(\"update transactions_attempts set attempt=attempt+1 where hash = ?\",\n\t\t\ttransactionHash).Error\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tta.Attempt++\n\t} else {\n\t\tta.Hash = transactionHash\n\t\tta.Attempt = 1\n\t\tif err = GetDB(dbTx).Create(ta).Error; err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\treturn int64(ta.Attempt), nil\n}\n\nfunc DecrementTxAttemptCount(dbTx *DbTransaction, transactionHash []byte) error {\n\treturn GetDB(dbTx).Exec(\"update transactions_attempts set attempt=attempt-1 where hash = ?\",\n\t\ttransactionHash).Error\n}\n\nfunc FindTxAttemptCount(dbTx *DbTransaction, count int) ([]*TransactionsAttempts, error) {\n\tvar rs []*TransactionsAttempts\n\tif err := GetDB(dbTx).Where(\"attempt > ?\", count).Find(&rs).Error; err != nil {\n\t\treturn rs, err\n\t}\n\treturn rs, nil\n}\n\n// GetByHash returns TransactionsAttempts existence by hash\nfunc DeleteTransactionsAttemptsByHash(dbTx *DbTransaction, hash []byte) error {\n\treturn GetDB(dbTx).Table(\"transactions_attempts\").Delete(&TransactionsAttempts{}, hash).Error\n}\n"
  },
  {
    "path": "packages/storage/sqldb/tx_record.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage sqldb\n\nimport (\n\t\"database/sql\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\nfunc GetTxRecord(tx *DbTransaction, hashStr string) (resultList []any, err error) {\n\tdb := GetDB(tx)\n\t// get record from rollback_tx\n\tvar (\n\t\trollbackTxs []RollbackTx\n\t)\n\terr = db.Table(\"rollback_tx\").Where(\"tx_hash = ?\", []byte(converter.HexToBin(hashStr))).Find(&rollbackTxs).Error\n\tif err != nil {\n\t\treturn\n\t}\n\tfor _, rtx := range rollbackTxs {\n\t\tid := rtx.TableID\n\t\tvar ecosystem string\n\t\ttableName := rtx.NameTable\n\t\tif tableName == `1_keys` || tableName == \"@system\" {\n\t\t\tcontinue\n\t\t}\n\t\tif strings.Contains(id, \",\") {\n\t\t\tids := strings.Split(id, \",\")\n\t\t\tif len(ids) == 2 {\n\t\t\t\tid, ecosystem = ids[0], ids[1]\n\t\t\t}\n\n\t\t}\n\t\tvar (\n\t\t\trows *sql.Rows\n\t\t\terr  error\n\t\t)\n\t\tif ecosystem == \"\" {\n\t\t\trows, err = db.Raw(`select * from \"` + tableName + `\" where id = ` + id).Rows()\n\t\t} else {\n\t\t\trows, err = db.Raw(`select * from \"` + tableName + `\" where id = ` + id + \" AND ecosystem = \" + ecosystem).Rows()\n\t\t}\n\t\tdefer rows.Close()\n\t\tif err == nil {\n\t\t\tcols, er := rows.Columns()\n\t\t\tif er != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvalues := make([][]byte, len(cols))\n\t\t\tscanArgs := make([]any, len(values))\n\t\t\tfor i := range values {\n\t\t\t\tscanArgs[i] = &values[i]\n\t\t\t}\n\t\t\tfor rows.Next() {\n\t\t\t\terr = rows.Scan(scanArgs...)\n\t\t\t\tif err == nil {\n\t\t\t\t\trow := make(map[string]any)\n\t\t\t\t\tfor i, col := range values {\n\t\t\t\t\t\tvar value string\n\t\t\t\t\t\tif col != nil {\n\t\t\t\t\t\t\tvalue = string(col)\n\t\t\t\t\t\t}\n\t\t\t\t\t\trow[cols[i]] = value\n\t\t\t\t\t}\n\t\t\t\t\tresultList = append(resultList, reflect.ValueOf(row).Interface())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "packages/storage/sqldb/upd_full_nodes.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage sqldb\n"
  },
  {
    "path": "packages/storage/sqldb/utxo_token.go",
    "content": "package sqldb\n\nimport (\n\t\"sync\"\n)\n\nvar (\n\tlock = &sync.RWMutex{}\n)\n\nfunc InsertTxOutputs(outputTxHash []byte, txOutputsMapCtx map[KeyUTXO][]SpentInfo, outputsMap map[KeyUTXO][]SpentInfo) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\tfor keyUTXO, txOutput := range txOutputsMapCtx {\n\t\tspentInfos := outputsMap[keyUTXO]\n\t\tfor i, _ := range txOutput {\n\t\t\ttxOutput[i].OutputTxHash = outputTxHash\n\t\t}\n\t\tspentInfos = append(spentInfos, txOutput...)\n\t\toutputsMap[keyUTXO] = spentInfos\n\t}\n}\n\nfunc UpdateTxInputs(inputTxHash []byte, txInputsMapCtx map[KeyUTXO][]SpentInfo, outputsMap map[KeyUTXO][]SpentInfo) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\tvar inputIndex int32\n\tfor txKeyUTXO, _ := range txInputsMapCtx {\n\t\tspentInfos := outputsMap[txKeyUTXO]\n\t\tfor i, info := range spentInfos {\n\t\t\tif len(info.InputTxHash) == 0 {\n\t\t\t\toutputsMap[txKeyUTXO][i].InputTxHash = inputTxHash\n\t\t\t\toutputsMap[txKeyUTXO][i].InputIndex = inputIndex\n\t\t\t\tinputIndex++\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc PutAllOutputsMap(outputs []SpentInfo, outputsMap map[KeyUTXO][]SpentInfo) {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\t//if len(outputsMap) == 0 {\n\t//\toutputsMap = make(map[KeyUTXO][]SpentInfo)\n\t//}\n\tfor _, output := range outputs {\n\t\tkeyUTXO := KeyUTXO{Ecosystem: output.Ecosystem, KeyId: output.OutputKeyId}\n\t\tspentInfos := outputsMap[keyUTXO]\n\t\tspentInfos = append(spentInfos, output)\n\n\t\tPutOutputsMap(keyUTXO, spentInfos, outputsMap)\n\t}\n}\nfunc PutOutputsMap(keyUTXO KeyUTXO, outputs []SpentInfo, outputsMap map[KeyUTXO][]SpentInfo) {\n\toutputsMap[keyUTXO] = outputs\n}\n\nfunc GetUnusedOutputsMap(keyUTXO KeyUTXO, outputsMap map[KeyUTXO][]SpentInfo) []SpentInfo {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\tspentInfos := outputsMap[keyUTXO]\n\tvar inputIndex int32\n\tvar list []SpentInfo\n\tfor _, output := range spentInfos {\n\t\tif len(output.InputTxHash) == 0 {\n\t\t\toutput.InputIndex = inputIndex\n\t\t\tinputIndex++\n\t\t\tlist = append(list, output)\n\t\t}\n\t}\n\treturn list\n}\n\nfunc GetAllOutputs(outputsMap map[KeyUTXO][]SpentInfo) []SpentInfo {\n\tvar list []SpentInfo\n\tfor _, outputs := range outputsMap {\n\t\tlist = append(list, outputs...)\n\t}\n\toutputsMap = make(map[KeyUTXO][]SpentInfo)\n\treturn list\n}\n"
  },
  {
    "path": "packages/storage/storage.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage storage\n"
  },
  {
    "path": "packages/system/system.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage system\n"
  },
  {
    "path": "packages/system/system_notwindows.go",
    "content": "//go:build !windows\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage system\n\nfunc killChildProc() {\n}\n"
  },
  {
    "path": "packages/system/system_windows.go",
    "content": "//go:build windows\n\n/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage system\n\nimport (\n\t\"os\"\n)\n\n/*\n#include <windows.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <TlHelp32.h>\n\nvoid kill_childproc( DWORD myprocID) {\n\tPROCESSENTRY32 pe;\n\n\tmemset(&pe, 0, sizeof(PROCESSENTRY32));\n\tpe.dwSize = sizeof(PROCESSENTRY32);\n\n\tHANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\n\tif (Process32First(hSnap, &pe))\n\t{\n\t    BOOL bContinue = TRUE;\n\n\t    while (bContinue)\n\t    {\n\t        if (pe.th32ParentProcessID == myprocID && memcmp( pe.szExeFile, \"tmp_\", 4 ) != 0 &&\n\t\t\t\tmemcmp(pe.szExeFile, \"chain\", 4) != 0)\n\t        {\n\t            HANDLE hChildProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);\n\n\t            if (hChildProc)\n\t            {\n\t\t\t\t\tkill_childproc(GetProcessId(hChildProc));\n\t                TerminateProcess(hChildProc, 1);\n\t                CloseHandle(hChildProc);\n\t            }\n\t        }\n\t        bContinue = Process32Next(hSnap, &pe);\n\t    }\n\t}\n}\n*/\nimport \"C\"\n\nfunc killChildProc() {\n\tC.kill_childproc(C.DWORD(os.Getpid()))\n}\n"
  },
  {
    "path": "packages/template/calculate.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage template\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\n\t\"github.com/shopspring/decimal\"\n)\n\nconst (\n\ttkNumber = iota\n\ttkAdd\n\ttkSub\n\ttkMul\n\ttkDiv\n\ttkLPar\n\ttkRPar\n\n\texpInt   = 0\n\texpFloat = 1\n\texpMoney = 2\n)\n\ntype token struct {\n\tType  int\n\tValue any\n}\n\ntype opFunc func()\n\nvar (\n\terrExp            = errors.New(`wrong expression`)\n\terrDiv            = errors.New(`dividing by zero`)\n\terrPrecIsNegative = errors.New(`precision is negative`)\n\terrWhere          = errors.New(`Where has wrong format`)\n)\n\nfunc parsing(input string, itype int) (*[]token, error) {\n\tvar err error\n\n\ttokens := make([]token, 0)\n\tnewToken := func(itype int, value any) {\n\t\ttokens = append(tokens, token{itype, value})\n\t}\n\tprevNumber := func() bool {\n\t\treturn len(tokens) > 0 && tokens[len(tokens)-1].Type == tkNumber\n\t}\n\tprevOper := func() bool {\n\t\treturn len(tokens) > 0 && (tokens[len(tokens)-1].Type >= tkAdd &&\n\t\t\ttokens[len(tokens)-1].Type <= tkDiv)\n\t}\n\tvar (\n\t\tnumlen int\n\t)\n\tops := map[rune]struct {\n\t\tid int\n\t\tpr int\n\t}{\n\t\t'+': {tkAdd, 1},\n\t\t'-': {tkSub, 1},\n\t\t'*': {tkMul, 2},\n\t\t'/': {tkDiv, 2},\n\t}\n\tfor off, ch := range input {\n\t\tif unicode.IsDigit(ch) || ch == '.' {\n\t\t\tnumlen++\n\t\t\tcontinue\n\t\t}\n\t\tif numlen > 0 {\n\t\t\tvar val any\n\n\t\t\tswitch itype {\n\t\t\tcase expInt:\n\t\t\t\tval, err = strconv.ParseInt(input[off-numlen:off], 10, 64)\n\t\t\tcase expFloat:\n\t\t\t\tval, err = strconv.ParseFloat(input[off-numlen:off], 64)\n\t\t\tcase expMoney:\n\t\t\t\tval, err = decimal.NewFromString(input[off-numlen : off])\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif prevNumber() {\n\t\t\t\treturn nil, errExp\n\t\t\t}\n\t\t\tnewToken(tkNumber, val)\n\t\t\tnumlen = 0\n\t\t}\n\t\tif item, ok := ops[ch]; ok {\n\t\t\tif prevOper() {\n\t\t\t\treturn nil, errExp\n\t\t\t}\n\t\t\tnewToken(item.id, item.pr)\n\t\t\tcontinue\n\t\t}\n\t\tswitch ch {\n\t\tcase '(':\n\t\t\tif prevNumber() {\n\t\t\t\treturn nil, errExp\n\t\t\t}\n\t\t\tnewToken(tkLPar, 3)\n\t\tcase ')':\n\t\t\tif prevOper() {\n\t\t\t\treturn nil, errExp\n\t\t\t}\n\t\t\tnewToken(tkRPar, 3)\n\t\tcase ' ', '\\t', '\\n', '\\r':\n\t\tdefault:\n\t\t\treturn nil, errExp\n\t\t}\n\t}\n\treturn &tokens, nil\n}\n\nfunc calcExp(tokens []token, resType int, prec string) string {\n\tvar top int\n\n\tstack := make([]any, 0, 16)\n\n\taddInt := func() {\n\t\tstack[top-1] = stack[top-1].(int64) + stack[top].(int64)\n\t}\n\taddFloat := func() {\n\t\tstack[top-1] = stack[top-1].(float64) + stack[top].(float64)\n\t}\n\taddMoney := func() {\n\t\tstack[top-1] = stack[top-1].(decimal.Decimal).Add(stack[top].(decimal.Decimal))\n\t}\n\tsubInt := func() {\n\t\tstack[top-1] = stack[top-1].(int64) - stack[top].(int64)\n\t}\n\tsubFloat := func() {\n\t\tstack[top-1] = stack[top-1].(float64) - stack[top].(float64)\n\t}\n\tsubMoney := func() {\n\t\tstack[top-1] = stack[top-1].(decimal.Decimal).Sub(stack[top].(decimal.Decimal))\n\t}\n\tmulInt := func() {\n\t\tstack[top-1] = stack[top-1].(int64) * stack[top].(int64)\n\t}\n\tmulFloat := func() {\n\t\tstack[top-1] = stack[top-1].(float64) * stack[top].(float64)\n\t}\n\tmulMoney := func() {\n\t\tstack[top-1] = stack[top-1].(decimal.Decimal).Mul(stack[top].(decimal.Decimal))\n\t}\n\tdivInt := func() {\n\t\tstack[top-1] = stack[top-1].(int64) / stack[top].(int64)\n\t}\n\tdivFloat := func() {\n\t\tstack[top-1] = stack[top-1].(float64) / stack[top].(float64)\n\t}\n\tdivMoney := func() {\n\t\tstack[top-1] = stack[top-1].(decimal.Decimal).Div(stack[top].(decimal.Decimal))\n\t}\n\n\tfuncs := map[int][]opFunc{\n\t\ttkAdd: {addInt, addFloat, addMoney},\n\t\ttkSub: {subInt, subFloat, subMoney},\n\t\ttkMul: {mulInt, mulFloat, mulMoney},\n\t\ttkDiv: {divInt, divFloat, divMoney},\n\t}\n\tfor _, item := range tokens {\n\t\tif item.Type == tkNumber {\n\t\t\tstack = append(stack, item.Value)\n\t\t} else {\n\t\t\tif len(stack) < 2 {\n\t\t\t\treturn errExp.Error()\n\t\t\t}\n\t\t\ttop = len(stack) - 1\n\t\t\tif item.Type == tkDiv {\n\t\t\t\tswitch resType {\n\t\t\t\tcase expInt:\n\t\t\t\t\tif stack[top].(int64) == 0 {\n\t\t\t\t\t\treturn errDiv.Error()\n\t\t\t\t\t}\n\t\t\t\tcase expFloat:\n\t\t\t\t\tif stack[top].(float64) == 0 {\n\t\t\t\t\t\treturn errDiv.Error()\n\t\t\t\t\t}\n\t\t\t\tcase expMoney:\n\t\t\t\t\tif stack[top].(decimal.Decimal).Cmp(decimal.Zero) == 0 {\n\t\t\t\t\t\treturn errDiv.Error()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfuncs[item.Type][resType]()\n\t\t\tstack = stack[:top]\n\t\t}\n\t}\n\tif len(stack) != 1 {\n\t\treturn errExp.Error()\n\t}\n\tif prec != \"\" {\n\t\tprecInt := converter.StrToInt(prec)\n\t\tif resType != expInt {\n\t\t\tif precInt < 0 {\n\t\t\t\treturn errPrecIsNegative.Error()\n\t\t\t}\n\t\t}\n\t\tif resType == expFloat {\n\t\t\treturn decimal.NewFromFloat(stack[0].(float64)).Round(int32(precInt)).String()\n\t\t}\n\t\tif resType == expMoney {\n\t\t\tmoney := stack[0].(decimal.Decimal)\n\t\t\treturn money.Round(int32(precInt)).String()\n\t\t}\n\t}\n\tif resType == expFloat {\n\t\tdecStr, _ := decimal.NewFromString(fmt.Sprintf(\"%f\", stack[0].(float64)))\n\t\treturn decStr.String()\n\t}\n\tif resType == expMoney {\n\t\treturn stack[0].(decimal.Decimal).String()\n\t}\n\treturn fmt.Sprint(stack[0])\n}\n\nfunc calculate(exp, etype, prec string) string {\n\tvar resType int\n\tif len(etype) == 0 && strings.Contains(exp, `.`) {\n\t\tetype = `float`\n\t}\n\tswitch etype {\n\tcase `float`:\n\t\tresType = expFloat\n\tcase `money`:\n\t\tresType = expMoney\n\t}\n\ttk, err := parsing(exp+` `, resType)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\tstack := make([]token, 0, len(*tk))\n\tbuf := make([]token, 0, 10)\n\tfor _, item := range *tk {\n\t\tswitch item.Type {\n\t\tcase tkNumber:\n\t\t\tstack = append(stack, item)\n\t\tcase tkLPar:\n\t\t\tbuf = append(buf, item)\n\t\tcase tkRPar:\n\t\t\ti := len(buf) - 1\n\t\t\tfor i >= 0 && buf[i].Type != tkLPar {\n\t\t\t\tstack = append(stack, buf[i])\n\t\t\t\ti--\n\t\t\t}\n\t\t\tif i < 0 {\n\t\t\t\treturn errExp.Error()\n\t\t\t}\n\t\t\tbuf = buf[:i]\n\t\tdefault:\n\t\t\tif len(buf) > 0 {\n\t\t\t\tlast := buf[len(buf)-1]\n\t\t\t\tif last.Type != tkLPar && last.Value.(int) >= item.Value.(int) {\n\t\t\t\t\tstack = append(stack, last)\n\t\t\t\t\tbuf[len(buf)-1] = item\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf = append(buf, item)\n\t\t}\n\t}\n\tfor i := len(buf) - 1; i >= 0; i-- {\n\t\tlast := buf[i]\n\t\tif last.Type >= tkAdd && last.Type <= tkDiv {\n\t\t\tstack = append(stack, last)\n\t\t} else {\n\t\t\treturn errExp.Error()\n\t\t}\n\t}\n\treturn calcExp(stack, resType, prec)\n}\n"
  },
  {
    "path": "packages/template/dbfind.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage template\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tcolumnTypeText     = \"text\"\n\tcolumnTypeLongText = \"long_text\"\n\tcolumnTypeBlob     = \"blob\"\n\n\tsubstringLength = 32\n\n\terrComma = `unexpected comma`\n)\n\nfunc dbfindExpressionBlob(column string) string {\n\treturn fmt.Sprintf(`md5(%s) \"%[1]s\"`, column)\n}\n\nfunc dbfindExpressionLongText(column string) string {\n\treturn fmt.Sprintf(`json_build_array(\n\t\tsubstr(%s, 1, %d),\n\t\tCASE WHEN length(%[1]s)>%[2]d THEN md5(%[1]s) END) \"%[1]s\"`, column, substringLength)\n}\n\ntype valueLink struct {\n\ttitle string\n\n\tid     string\n\ttable  string\n\tcolumn string\n\thash   string\n}\n\nfunc (vl *valueLink) link() string {\n\tif len(vl.hash) > 0 {\n\t\treturn fmt.Sprintf(\"/data/%s/%s/%s/%s\", vl.table, vl.id, vl.column, vl.hash)\n\t}\n\treturn \"\"\n}\n\nfunc (vl *valueLink) marshal() (string, error) {\n\tb, err := json.Marshal(map[string]string{\n\t\t\"title\": vl.title,\n\t\t\"link\":  vl.link(),\n\t})\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marshalling valueLink to JSON\")\n\t\treturn \"\", err\n\t}\n\treturn string(b), nil\n}\n\nfunc trimString(in []rune) string {\n\tout := strings.TrimSpace(string(in))\n\tif len(out) > 0 && out[0] == '\"' && out[len(out)-1] == '\"' {\n\t\tout = out[1 : len(out)-1]\n\t}\n\treturn out\n}\n\nfunc ParseObject(in []rune) (any, int, error) {\n\tvar (\n\t\tret            any\n\t\tkey            string\n\t\tmapMode, quote bool\n\t)\n\n\tlength := len(in)\n\tif in[0] == '[' {\n\t\tret = make([]any, 0)\n\t} else if in[0] == '{' {\n\t\tret = types.NewMap()\n\t\tmapMode = true\n\t} else {\n\t\treturn nil, 0, errWhere\n\t}\n\taddEmptyKey := func() {\n\t\tif mapMode {\n\t\t\tret.(*types.Map).Set(key, \"\")\n\t\t} else if len(key) > 0 {\n\t\t\tret = append(ret.([]any), types.LoadMap(map[string]any{key: ``}))\n\t\t}\n\t\tkey = ``\n\t}\n\tstart := 1\n\ti := 1\n\tprev := ' '\nmain:\n\tfor ; i < length; i++ {\n\t\tch := in[i]\n\t\tif quote && ch != '\"' {\n\t\t\tcontinue\n\t\t}\n\t\tswitch ch {\n\t\tcase ']':\n\t\t\tif !mapMode {\n\t\t\t\tbreak main\n\t\t\t}\n\t\tcase '}':\n\t\t\tif mapMode {\n\t\t\t\tbreak main\n\t\t\t}\n\t\tcase '{', '[':\n\t\t\tpar, off, err := ParseObject(in[i:])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, i, err\n\t\t\t}\n\t\t\tif mapMode {\n\t\t\t\tif len(key) == 0 {\n\t\t\t\t\tswitch v := par.(type) {\n\t\t\t\t\tcase map[string]any:\n\t\t\t\t\t\tfor ikey, ival := range v {\n\t\t\t\t\t\t\tret.(*types.Map).Set(ikey, ival)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tret.(*types.Map).Set(key, par)\n\t\t\t\t\tkey = ``\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif len(key) > 0 {\n\t\t\t\t\tpar = types.LoadMap(map[string]any{key: par})\n\t\t\t\t\tkey = ``\n\t\t\t\t}\n\t\t\t\tret = append(ret.([]any), par)\n\t\t\t}\n\t\t\ti += off\n\t\t\tstart = i + 1\n\t\tcase '\"':\n\t\t\tquote = !quote\n\t\tcase ':':\n\t\t\tif len(key) == 0 {\n\t\t\t\tkey = trimString(in[start:i])\n\t\t\t\tstart = i + 1\n\t\t\t}\n\t\tcase ',':\n\t\t\tval := trimString(in[start:i])\n\t\t\tif prev == ch {\n\t\t\t\treturn nil, i, fmt.Errorf(errComma)\n\t\t\t}\n\t\t\tif len(val) == 0 && len(key) > 0 {\n\t\t\t\taddEmptyKey()\n\t\t\t}\n\t\t\tif len(val) > 0 {\n\t\t\t\tif mapMode {\n\t\t\t\t\tret.(*types.Map).Set(key, val)\n\t\t\t\t\tkey = ``\n\t\t\t\t} else {\n\t\t\t\t\tif len(key) > 0 {\n\t\t\t\t\t\tret = append(ret.([]any), types.LoadMap(map[string]any{key: val}))\n\t\t\t\t\t\tkey = ``\n\t\t\t\t\t} else {\n\t\t\t\t\t\tret = append(ret.([]any), val)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tstart = i + 1\n\t\t}\n\t\tif ch != ' ' {\n\t\t\tprev = ch\n\t\t}\n\t}\n\tif prev == ',' {\n\t\treturn nil, i, fmt.Errorf(errComma)\n\t}\n\tif start < i {\n\t\tif last := trimString(in[start:i]); len(last) > 0 {\n\t\t\tif mapMode {\n\t\t\t\tret.(*types.Map).Set(key, last)\n\t\t\t} else {\n\t\t\t\tif len(key) > 0 {\n\t\t\t\t\tret = append(ret.([]any), types.LoadMap(map[string]any{key: last}))\n\t\t\t\t\tkey = ``\n\t\t\t\t} else {\n\t\t\t\t\tret = append(ret.([]any), last)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if len(key) > 0 {\n\t\t\taddEmptyKey()\n\t\t}\n\t}\n\tswitch v := ret.(type) {\n\tcase *types.Map:\n\t\tif v.Size() == 0 {\n\t\t\tret = ``\n\t\t}\n\tcase map[string]any:\n\t\tif len(v) == 0 {\n\t\t\tret = ``\n\t\t}\n\tcase []any:\n\t\tif len(v) == 0 {\n\t\t\tret = ``\n\t\t}\n\t}\n\treturn ret, i, nil\n}\n"
  },
  {
    "path": "packages/template/funcs.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage template\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/language\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tqb \"github.com/IBAX-io/go-ibax/packages/storage/sqldb/queryBuilder\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// Composite represents a composite contract\ntype Composite struct {\n\tName string `json:\"name\"`\n\tData any    `json:\"data,omitempty\"`\n}\n\n// Action describes a button action\ntype Action struct {\n\tName   string            `json:\"name\"`\n\tParams map[string]string `json:\"params,omitempty\"`\n}\n\nvar (\n\tfuncs = make(map[string]tplFunc)\n\ttails = make(map[string]forTails)\n\tmodes = [][]rune{{'(', ')'}, {'{', '}'}, {'[', ']'}}\n)\n\nconst (\n\tcolumnNameKey = \"column_name\"\n\tdataTypeKey   = \"data_type\"\n)\n\nfunc init() {\n\tfuncs[`Lower`] = tplFunc{lowerTag, defaultTag, `lower`, `Text`}\n\tfuncs[`AddToolButton`] = tplFunc{defaultTailTag, defaultTailTag, `addtoolbutton`, `Title,Icon,Page,PageParams`}\n\tfuncs[`Address`] = tplFunc{addressTag, defaultTag, `address`, `Wallet`}\n\tfuncs[`PubToID`] = tplFunc{pubToIdTag, defaultTag, `pubtoid`, `Pub`}\n\tfuncs[`AddressToId`] = tplFunc{addressIDTag, defaultTag, `addresstoid`, `Wallet`}\n\tfuncs[`AppParam`] = tplFunc{appparTag, defaultTag, `apppar`, `Name,App,Index,Source,Ecosystem`}\n\tfuncs[`Calculate`] = tplFunc{calculateTag, defaultTag, `calculate`, `Exp,Type,Prec`}\n\tfuncs[`CmpTime`] = tplFunc{cmpTimeTag, defaultTag, `cmptime`, `Time1,Time2`}\n\tfuncs[`Code`] = tplFunc{defaultTag, defaultTag, `code`, `Text`}\n\tfuncs[`CodeAsIs`] = tplFunc{defaultTag, defaultTag, `code`, `#Text`}\n\tfuncs[`DateTime`] = tplFunc{dateTimeTag, defaultTag, `datetime`, `DateTime,Format,Location`}\n\tfuncs[`EcosysParam`] = tplFunc{ecosysparTag, defaultTag, `ecosyspar`, `Name,Index,Source,Ecosystem`}\n\tfuncs[`Em`] = tplFunc{defaultTag, defaultTag, `em`, `Body,Class`}\n\tfuncs[`GetVar`] = tplFunc{getvarTag, defaultTag, `getvar`, `Name`}\n\tfuncs[`GetHistory`] = tplFunc{getHistoryTag, defaultTag, `gethistory`,\n\t\t`Source,Name,Id,RollbackId`}\n\tfuncs[`Hint`] = tplFunc{defaultTag, defaultTag, `hint`, `Icon,Title,Text`}\n\tfuncs[`ImageInput`] = tplFunc{defaultTag, defaultTag, `imageinput`, `Name,Width,Ratio,Format`}\n\tfuncs[`InputErr`] = tplFunc{defaultTag, defaultTag, `inputerr`, `*`}\n\tfuncs[`JsonToSource`] = tplFunc{jsontosourceTag, defaultTag, `jsontosource`, `Source,Data,Prefix`}\n\tfuncs[`ArrayToSource`] = tplFunc{arraytosourceTag, defaultTag, `arraytosource`, `Source,Data,Prefix`}\n\tfuncs[`LangRes`] = tplFunc{langresTag, defaultTag, `langres`, `Name,Lang`}\n\tfuncs[`MenuGroup`] = tplFunc{menugroupTag, defaultTag, `menugroup`, `Title,Body,Icon`}\n\tfuncs[`MenuItem`] = tplFunc{defaultTag, defaultTag, `menuitem`, `Title,Page,PageParams,Icon,Clb`}\n\tfuncs[`Money`] = tplFunc{moneyTag, defaultTag, `money`, `Exp,Digit`}\n\tfuncs[`Range`] = tplFunc{rangeTag, defaultTag, `range`, `Source,From,To,Step`}\n\tfuncs[`SetTitle`] = tplFunc{defaultTag, defaultTag, `settitle`, `Title`}\n\tfuncs[`SetVar`] = tplFunc{setvarTag, defaultTag, `setvar`, `Name,Value`}\n\tfuncs[`Strong`] = tplFunc{defaultTag, defaultTag, `strong`, `Body,Class`}\n\tfuncs[`SysParam`] = tplFunc{sysparTag, defaultTag, `syspar`, `Name`}\n\tfuncs[`Button`] = tplFunc{buttonTag, buttonTag, `button`, `Body,Page,Class,Contract,Params,PageParams`}\n\tfuncs[`Div`] = tplFunc{defaultTailTag, defaultTailTag, `div`, `Class,Body`}\n\tfuncs[`ForList`] = tplFunc{forlistTag, defaultTag, `forlist`, `Source,Data,Index`}\n\tfuncs[`Form`] = tplFunc{defaultTailTag, defaultTailTag, `form`, `Class,Body`}\n\tfuncs[`If`] = tplFunc{ifTag, ifFull, `if`, `Condition,Body`}\n\tfuncs[`Image`] = tplFunc{imageTag, defaultTailTag, `image`, `Src,Alt,Class`}\n\tfuncs[`Include`] = tplFunc{includeTag, defaultTag, `include`, `Name`}\n\tfuncs[`Input`] = tplFunc{defaultTailTag, defaultTailTag, `input`, `Name,Class,Placeholder,Type,Value,Disabled`}\n\tfuncs[`Label`] = tplFunc{defaultTailTag, defaultTailTag, `label`, `Body,Class,For`}\n\tfuncs[`LinkPage`] = tplFunc{defaultTailTag, defaultTailTag, `linkpage`, `Body,Page,Class,PageParams`}\n\tfuncs[`Data`] = tplFunc{dataTag, defaultTailTag, `data`, `Source,Columns,Data`}\n\tfuncs[`DBFind`] = tplFunc{dbfindTag, defaultTailTag, `dbfind`, `Name,Source`}\n\tfuncs[`And`] = tplFunc{andTag, defaultTag, `and`, `*`}\n\tfuncs[`Or`] = tplFunc{orTag, defaultTag, `or`, `*`}\n\tfuncs[`P`] = tplFunc{defaultTailTag, defaultTailTag, `p`, `Body,Class`}\n\tfuncs[`RadioGroup`] = tplFunc{defaultTailTag, defaultTailTag, `radiogroup`, `Name,Source,NameColumn,ValueColumn,Value,Class`}\n\tfuncs[`Span`] = tplFunc{defaultTailTag, defaultTailTag, `span`, `Body,Class`}\n\tfuncs[`QRcode`] = tplFunc{defaultTag, defaultTag, `qrcode`, `Text`}\n\tfuncs[`Table`] = tplFunc{tableTag, defaultTailTag, `table`, `Source,Columns`}\n\tfuncs[`Select`] = tplFunc{defaultTailTag, defaultTailTag, `select`, `Name,Source,NameColumn,ValueColumn,Value,Class`}\n\tfuncs[`Chart`] = tplFunc{chartTag, defaultTailTag, `chart`, `Type,Source,FieldLabel,FieldValue,Colors`}\n\tfuncs[`InputMap`] = tplFunc{defaultTailTag, defaultTailTag, \"inputMap\", \"Name,@Value,Type,MapType\"}\n\tfuncs[`Map`] = tplFunc{defaultTag, defaultTag, \"map\", \"@Value,MapType,Hmap\"}\n\tfuncs[`Binary`] = tplFunc{binaryTag, defaultTag, \"binary\", \"AppID,Name,Account\"}\n\tfuncs[`GetColumnType`] = tplFunc{columntypeTag, defaultTag, `columntype`, `Table,Column`}\n\tfuncs[`VarAsIs`] = tplFunc{varasisTag, defaultTag, `varasis`, `Name,Value`}\n\n\ttails[`addtoolbutton`] = forTails{map[string]tailInfo{\n\t\t`Popup`: {tplFunc{popupTag, defaultTailFull, `popup`, `Width,Header`}, true},\n\t}}\n\ttails[`button`] = forTails{map[string]tailInfo{\n\t\t`Action`:            {tplFunc{actionTag, defaultTailFull, `action`, `Name,Params`}, false},\n\t\t`Alert`:             {tplFunc{alertTag, defaultTailFull, `alert`, `Text,ConfirmButton,CancelButton,Icon`}, true},\n\t\t`Popup`:             {tplFunc{popupTag, defaultTailFull, `popup`, `Width,Header`}, true},\n\t\t`Style`:             {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t\t`CompositeContract`: {tplFunc{compositeTag, defaultTailFull, `composite`, `Name,Data`}, false},\n\t\t`ErrorRedirect`: {tplFunc{errredirTag, defaultTailFull, `errorredirect`,\n\t\t\t`ErrorID,PageName,PageParams`}, false},\n\t}}\n\ttails[`div`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t\t`Show`:  {tplFunc{showTag, defaultTailFull, `show`, `Condition`}, false},\n\t\t`Hide`:  {tplFunc{hideTag, defaultTailFull, `hide`, `Condition`}, false},\n\t}}\n\ttails[`form`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`if`] = forTails{map[string]tailInfo{\n\t\t`Else`:   {tplFunc{elseTag, elseFull, `else`, `Body`}, true},\n\t\t`ElseIf`: {tplFunc{elseifTag, elseifFull, `elseif`, `Condition,Body`}, false},\n\t}}\n\ttails[`image`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`input`] = forTails{map[string]tailInfo{\n\t\t`Validate`: {tplFunc{validateTag, validateFull, `validate`, `*`}, false},\n\t\t`Style`:    {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`label`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`linkpage`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`data`] = forTails{map[string]tailInfo{\n\t\t`Custom`: {tplFunc{customTag, customTagFull, `custom`, `Column,Body`}, false},\n\t}}\n\ttails[`dbfind`] = forTails{map[string]tailInfo{\n\t\t`Columns`: {tplFunc{tailTag, defaultTailFull, `columns`, `Columns`}, false},\n\t\t`Count`:   {tplFunc{tailTag, defaultTailFull, `count`, `CountVar`}, false},\n\t\t`Where`:   {tplFunc{tailTag, defaultTailFull, `where`, `Where`}, false},\n\t\t`WhereId`: {tplFunc{tailTag, defaultTailFull, `whereid`, `WhereId`}, false},\n\t\t`Order`:   {tplFunc{tailTag, defaultTailFull, `order`, `Order`}, false},\n\t\t`Limit`:   {tplFunc{tailTag, defaultTailFull, `limit`, `Limit`}, false},\n\t\t`Offset`:  {tplFunc{tailTag, defaultTailFull, `offset`, `Offset`}, false},\n\t\t`Custom`:  {tplFunc{customTag, customTagFull, `custom`, `Column,Body`}, false},\n\t\t`Vars`:    {tplFunc{tailTag, defaultTailFull, `vars`, `Prefix`}, false},\n\t\t`Cutoff`:  {tplFunc{tailTag, defaultTailFull, `cutoff`, `Cutoff`}, false},\n\t}}\n\ttails[`p`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`radiogroup`] = forTails{map[string]tailInfo{\n\t\t`Validate`: {tplFunc{validateTag, validateFull, `validate`, `*`}, false},\n\t\t`Style`:    {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`span`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`table`] = forTails{map[string]tailInfo{\n\t\t`Style`: {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`select`] = forTails{map[string]tailInfo{\n\t\t`Validate`: {tplFunc{validateTag, validateFull, `validate`, `*`}, false},\n\t\t`Style`:    {tplFunc{tailTag, defaultTailFull, `style`, `Style`}, false},\n\t}}\n\ttails[`inputMap`] = forTails{map[string]tailInfo{\n\t\t`Validate`: {tplFunc{validateTag, validateFull, `validate`, `*`}, false},\n\t}}\n\ttails[`binary`] = forTails{map[string]tailInfo{\n\t\t`ById`:      {tplFunc{tailTag, defaultTailFull, `id`, `id`}, false},\n\t\t`Ecosystem`: {tplFunc{tailTag, defaultTailFull, `ecosystem`, `ecosystem`}, false},\n\t}}\n}\n\nfunc defaultTag(par parFunc) string {\n\tsetAllAttr(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc lowerTag(par parFunc) string {\n\treturn strings.ToLower(macro((*par.Pars)[`Text`], par.Workspace.Vars))\n}\n\nfunc moneyTag(par parFunc) string {\n\tvar cents int64\n\tif len((*par.Pars)[`Digit`]) > 0 {\n\t\tcents = converter.StrToInt64(macro((*par.Pars)[`Digit`], par.Workspace.Vars))\n\t} else {\n\t\tecosystem := getVar(par.Workspace, `ecosystem_id`)\n\t\tsp := &sqldb.Ecosystem{}\n\t\t_, err := sp.Get(nil, converter.StrToInt64(ecosystem))\n\t\tif err != nil {\n\t\t\treturn `0`\n\t\t}\n\t\tcents = sp.Digits\n\t}\n\texp := macro((*par.Pars)[`Exp`], par.Workspace.Vars)\n\tm, err := converter.FormatMoney(exp, int32(cents))\n\tif err != nil {\n\t\treturn `0`\n\t}\n\treturn m\n}\n\nfunc menugroupTag(par parFunc) string {\n\tsetAllAttr(par)\n\tname := (*par.Pars)[`Title`]\n\tif par.RawPars != nil {\n\t\tif v, ok := (*par.RawPars)[`Title`]; ok {\n\t\t\tname = v\n\t\t}\n\t}\n\tpar.Node.Attr[`name`] = name\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc forlistTag(par parFunc) (ret string) {\n\tvar (\n\t\tname, indexName string\n\t)\n\tsetAllAttr(par)\n\tif len((*par.Pars)[`Source`]) > 0 {\n\t\tname = par.Node.Attr[`source`].(string)\n\t}\n\tif len((*par.Pars)[`Index`]) > 0 {\n\t\tindexName = par.Node.Attr[`index`].(string)\n\t} else {\n\t\tindexName = name + `_index`\n\t}\n\tif len(name) == 0 || par.Workspace.Sources == nil {\n\t\treturn\n\t}\n\tsource := (*par.Workspace.Sources)[name]\n\tif source.Data == nil {\n\t\treturn\n\t}\n\troot := node{}\n\tkeys := make(map[string]bool)\n\tfor key := range *par.Workspace.Vars {\n\t\tkeys[key] = true\n\t}\n\tfor index, item := range *source.Data {\n\t\tvals := map[string]string{indexName: converter.IntToStr(index + 1)}\n\t\tfor i, icol := range *source.Columns {\n\t\t\tvals[icol] = item[i]\n\t\t}\n\t\tif index > 0 {\n\t\t\tfor key := range *par.Workspace.Vars {\n\t\t\t\tif !keys[key] {\n\t\t\t\t\tdelete(*par.Workspace.Vars, key)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor key, item := range vals {\n\t\t\tsetVar(par.Workspace, key, item)\n\t\t}\n\t\tprocess((*par.Pars)[`Data`], &root, par.Workspace)\n\t\tfor _, item := range root.Children {\n\t\t\tif item.Tag == `text` {\n\t\t\t\titem.Text = macroReplace(item.Text, par.Workspace.Vars)\n\t\t\t}\n\t\t}\n\t\tfor key := range vals {\n\t\t\tdelete(*par.Workspace.Vars, key)\n\t\t}\n\t}\n\tpar.Node.Children = root.Children\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn\n}\n\nfunc addressTag(par parFunc) string {\n\tidval := (*par.Pars)[`Wallet`]\n\tif len(idval) == 0 {\n\t\tidval = getVar(par.Workspace, `key_id`)\n\t}\n\tidval = processToText(par, macro(idval, par.Workspace.Vars))\n\tid, _ := strconv.ParseInt(idval, 10, 64)\n\tif id == 0 {\n\t\treturn `unknown address`\n\t}\n\treturn converter.AddressToString(id)\n}\n\nfunc pubToIdTag(par parFunc) string {\n\thexkey := (*par.Pars)[`Pub`]\n\tif len(hexkey) == 0 {\n\t\treturn `0`\n\t}\n\tidval := processToText(par, macro(hexkey, par.Workspace.Vars))\n\tpubkey, err := crypto.HexToPub(idval)\n\tif err != nil {\n\t\treturn `0`\n\t}\n\treturn converter.Int64ToStr(crypto.Address(pubkey))\n}\n\nfunc addressIDTag(par parFunc) string {\n\taddress := (*par.Pars)[`Wallet`]\n\tif len(address) == 0 {\n\t\treturn getVar(par.Workspace, `key_id`)\n\t}\n\tid := converter.AddressToID(processToText(par, macro(address, par.Workspace.Vars)))\n\tif id == 0 {\n\t\treturn `0`\n\t}\n\treturn converter.Int64ToStr(id)\n}\n\nfunc calculateTag(par parFunc) string {\n\treturn calculate(macro((*par.Pars)[`Exp`], par.Workspace.Vars), (*par.Pars)[`Type`],\n\t\tmacro((*par.Pars)[`Prec`], par.Workspace.Vars))\n}\n\nfunc paramToSource(par parFunc, val string) string {\n\tdata := make([][]string, 0)\n\tcols := []string{`id`, `name`}\n\ttypes := []string{`text`, `text`}\n\tfor key, item := range strings.Split(val, `,`) {\n\t\titem, _ = language.LangText(nil, item,\n\t\t\tconverter.StrToInt(getVar(par.Workspace, `ecosystem_id`)), getVar(par.Workspace, `lang`))\n\t\tdata = append(data, []string{converter.IntToStr(key + 1), item})\n\t}\n\tnode := node{Tag: `data`, Attr: map[string]any{`columns`: &cols, `types`: &types,\n\t\t`data`: &data, `source`: (*par.Pars)[`Source`]}}\n\tpar.Owner.Children = append(par.Owner.Children, &node)\n\n\tpar.Workspace.SetSource((*par.Pars)[`Source`], &Source{\n\t\tColumns: node.Attr[`columns`].(*[]string),\n\t\tData:    node.Attr[`data`].(*[][]string),\n\t})\n\n\treturn ``\n}\n\nfunc paramToIndex(par parFunc, val string) (ret string) {\n\tind := converter.StrToInt(macro((*par.Pars)[`Index`], par.Workspace.Vars))\n\tif alist := strings.Split(val, `,`); ind > 0 && len(alist) >= ind {\n\t\tret, _ = language.LangText(nil, alist[ind-1],\n\t\t\tconverter.StrToInt(getVar(par.Workspace, `ecosystem_id`)),\n\t\t\tgetVar(par.Workspace, `lang`))\n\t}\n\treturn\n}\n\nfunc ecosysparTag(par parFunc) string {\n\tif len((*par.Pars)[`Name`]) == 0 {\n\t\treturn ``\n\t}\n\tecosystem := getVar(par.Workspace, `ecosystem_id`)\n\tif len((*par.Pars)[`Ecosystem`]) != 0 {\n\t\tecosystem = macro((*par.Pars)[`Ecosystem`], par.Workspace.Vars)\n\t}\n\tsp := &sqldb.StateParameter{}\n\tsp.SetTablePrefix(ecosystem)\n\tparameterName := macro((*par.Pars)[`Name`], par.Workspace.Vars)\n\t_, err := sp.Get(nil, parameterName)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting ecosystem param\")\n\t\treturn err.Error()\n\t}\n\tval := sp.Value\n\tif len((*par.Pars)[`Source`]) > 0 {\n\t\treturn paramToSource(par, val)\n\t}\n\tif len((*par.Pars)[`Index`]) > 0 {\n\t\tval = paramToIndex(par, val)\n\t}\n\treturn val\n}\n\nfunc appparTag(par parFunc) string {\n\tif len((*par.Pars)[`Name`]) == 0 || len((*par.Pars)[`App`]) == 0 {\n\t\treturn ``\n\t}\n\tecosystem := getVar(par.Workspace, `ecosystem_id`)\n\tif len((*par.Pars)[`Ecosystem`]) != 0 {\n\t\tecosystem = macro((*par.Pars)[`Ecosystem`], par.Workspace.Vars)\n\t}\n\tap := &sqldb.AppParam{}\n\tap.SetTablePrefix(ecosystem)\n\t_, err := ap.Get(nil, converter.StrToInt64(macro((*par.Pars)[`App`], par.Workspace.Vars)),\n\t\tmacro((*par.Pars)[`Name`], par.Workspace.Vars))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting app param\")\n\t\treturn err.Error()\n\t}\n\tval := ap.Value\n\tif len((*par.Pars)[`Source`]) > 0 {\n\t\treturn paramToSource(par, val)\n\t}\n\tif len((*par.Pars)[`Index`]) > 0 {\n\t\tval = paramToIndex(par, val)\n\t}\n\treturn val\n}\n\nfunc langresTag(par parFunc) string {\n\tlang := (*par.Pars)[`Lang`]\n\tif len(lang) == 0 {\n\t\tlang = getVar(par.Workspace, `lang`)\n\t}\n\tret, _ := language.LangText(nil, (*par.Pars)[`Name`],\n\t\tint(converter.StrToInt64(getVar(par.Workspace, `ecosystem_id`))), lang)\n\treturn ret\n}\n\nfunc sysparTag(par parFunc) (ret string) {\n\tif len((*par.Pars)[`Name`]) > 0 {\n\t\tret = syspar.SysString(macro((*par.Pars)[`Name`], par.Workspace.Vars))\n\t}\n\treturn\n}\n\nfunc andTag(par parFunc) string {\n\tcount := len(*par.Pars)\n\tfor i := 0; i < count; i++ {\n\t\tif !ifValue((*par.Pars)[strconv.Itoa(i)], par.Workspace) {\n\t\t\treturn `0`\n\t\t}\n\t}\n\treturn `1`\n}\n\nfunc orTag(par parFunc) string {\n\tcount := len(*par.Pars)\n\tfor i := 0; i < count; i++ {\n\t\tif ifValue((*par.Pars)[strconv.Itoa(i)], par.Workspace) {\n\t\t\treturn `1`\n\t\t}\n\t}\n\treturn `0`\n}\n\nfunc alertTag(par parFunc) string {\n\tsetAllAttr(par)\n\tpar.Owner.Attr[`alert`] = par.Node.Attr\n\treturn ``\n}\n\nfunc actionTag(par parFunc) string {\n\tsetAllAttr(par)\n\tif len((*par.Pars)[`Name`]) == 0 {\n\t\treturn ``\n\t}\n\tif par.Owner.Attr[`action`] == nil {\n\t\tpar.Owner.Attr[`action`] = make([]Action, 0)\n\t}\n\tvar params map[string]string\n\tif v, ok := par.Node.Attr[\"params\"]; ok {\n\t\tparams = make(map[string]string)\n\t\tfor key, val := range v.(map[string]any) {\n\t\t\tif imap, ok := val.(map[string]any); ok {\n\t\t\t\tparams[key] = macro(fmt.Sprint(imap[\"text\"]), par.Workspace.Vars)\n\t\t\t} else {\n\t\t\t\tparams[key] = macro(fmt.Sprint(val), par.Workspace.Vars)\n\t\t\t}\n\t\t}\n\t}\n\tpar.Owner.Attr[`action`] = append(par.Owner.Attr[`action`].([]Action),\n\t\tAction{\n\t\t\tName:   macro((*par.Pars)[`Name`], par.Workspace.Vars),\n\t\t\tParams: params,\n\t\t})\n\treturn ``\n}\n\nfunc defaultTailFull(par parFunc) string {\n\tsetAllAttr(par)\n\tpar.Owner.Tail = append(par.Owner.Tail, par.Node)\n\treturn ``\n}\n\nfunc dataTag(par parFunc) string {\n\tsetAllAttr(par)\n\tdefaultTail(par, `data`)\n\n\tdata := make([][]string, 0)\n\tcols := strings.Split((*par.Pars)[`Columns`], `,`)\n\ttypes := make([]string, len(cols))\n\tfor i := 0; i < len(types); i++ {\n\t\ttypes[i] = `text`\n\t}\n\n\tlist, err := csv.NewReader(strings.NewReader((*par.Pars)[`Data`])).ReadAll()\n\tif err != nil {\n\t\tinput := strings.Split((*par.Pars)[`Data`], \"\\n\")\n\t\tpar.Node.Attr[`error`] = err.Error()\n\t\tprefix := `line `\n\t\tfor err != nil && strings.HasPrefix(err.Error(), prefix) {\n\t\t\terrText := err.Error()\n\t\t\tline := converter.StrToInt64(errText[len(prefix):strings.IndexByte(errText, ',')])\n\t\t\tif line < 1 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tinput = append(input[:line-1], input[line:]...)\n\t\t\tlist, err = csv.NewReader(strings.NewReader(strings.Join(input, \"\\n\"))).ReadAll()\n\t\t}\n\t}\n\tlencol := 0\n\tdefcol := 0\n\tfor _, item := range list {\n\t\tif lencol == 0 {\n\t\t\tdefcol = len(cols)\n\t\t\tif par.Node.Attr[`customs`] != nil {\n\t\t\t\tfor _, v := range par.Node.Attr[`customs`].([]string) {\n\t\t\t\t\tcols = append(cols, v)\n\t\t\t\t\ttypes = append(types, `tags`)\n\t\t\t\t}\n\t\t\t}\n\t\t\tlencol = len(cols)\n\t\t}\n\t\trow := make([]string, lencol)\n\t\tvals := make(map[string]Var)\n\t\tfor i, icol := range cols {\n\t\t\tvar ival string\n\t\t\tif i < defcol {\n\t\t\t\tif i < len(item) {\n\t\t\t\t\tival = strings.TrimSpace(item[i])\n\t\t\t\t}\n\t\t\t\tvals[icol] = Var{Value: ival}\n\t\t\t} else {\n\t\t\t\troot := node{}\n\t\t\t\tfor key, item := range vals {\n\t\t\t\t\t(*par.Workspace.Vars)[key] = item\n\t\t\t\t}\n\t\t\t\tprocess(par.Node.Attr[`custombody`].([]string)[i-defcol], &root, par.Workspace)\n\t\t\t\tfor key := range vals {\n\t\t\t\t\tdelete(*par.Workspace.Vars, key)\n\t\t\t\t}\n\t\t\t\tout, err := json.Marshal(root.Children)\n\t\t\t\tif err == nil {\n\t\t\t\t\tival = macro(string(out), &vals)\n\t\t\t\t} else {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marshalling custombody to JSON\")\n\t\t\t\t}\n\t\t\t}\n\t\t\trow[i] = ival\n\t\t}\n\t\tdata = append(data, row)\n\t}\n\tsetAllAttr(par)\n\tdelete(par.Node.Attr, `customs`)\n\tdelete(par.Node.Attr, `custombody`)\n\tpar.Node.Attr[`columns`] = &cols\n\tpar.Node.Attr[`types`] = &types\n\tpar.Node.Attr[`data`] = &data\n\tnewSource(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc dbfindTag(par parFunc) string {\n\tvar (\n\t\tinColumns any\n\t\tcolumns   []string\n\t\tstate     int64\n\t\terr       error\n\t\tperm      map[string]string\n\t\toffset    string\n\n\t\tcutoffColumns   = make(map[string]bool)\n\t\textendedColumns = make(map[string]string)\n\t\tqueryColumns    = make([]string, 0)\n\t)\n\tif len((*par.Pars)[`Name`]) == 0 {\n\t\treturn ``\n\t}\n\tdefaultTail(par, `dbfind`)\n\tprefix := ``\n\twhere := ``\n\torder := ``\n\tlimit := 25\n\n\tif par.Node.Attr[`columns`] != nil {\n\t\tfields := par.Node.Attr[`columns`].(string)\n\t\tif strings.HasPrefix(fields, `[`) {\n\t\t\tinColumns, _, err = ParseObject([]rune(fields))\n\t\t\tif err != nil {\n\t\t\t\treturn err.Error()\n\t\t\t}\n\t\t} else {\n\t\t\tinColumns = fields\n\t\t}\n\t}\n\tcolumns, err = qb.GetColumns(inColumns)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\tif par.Node.Attr[`where`] != nil {\n\t\twhere = macro(par.Node.Attr[`where`].(string), par.Workspace.Vars)\n\t\tif strings.HasPrefix(where, `{`) {\n\t\t\tinWhere, _, err := ParseObject([]rune(where))\n\t\t\tif err != nil {\n\t\t\t\treturn err.Error()\n\t\t\t}\n\t\t\tswitch v := inWhere.(type) {\n\t\t\tcase string:\n\t\t\t\tif len(v) == 0 {\n\t\t\t\t\twhere = `true`\n\t\t\t\t} else {\n\t\t\t\t\treturn errWhere.Error()\n\t\t\t\t}\n\t\t\tcase map[string]any:\n\t\t\t\twhere, err = qb.GetWhere(types.LoadMap(v))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err.Error()\n\t\t\t\t}\n\t\t\tcase *types.Map:\n\t\t\t\twhere, err = qb.GetWhere(v)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err.Error()\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn errWhere.Error()\n\t\t\t}\n\t\t} else if len(where) > 0 {\n\t\t\treturn errWhere.Error()\n\t\t}\n\t}\n\tif par.Node.Attr[`whereid`] != nil {\n\t\twhere = fmt.Sprintf(` id='%d'`, converter.StrToInt64(macro(par.Node.Attr[`whereid`].(string), par.Workspace.Vars)))\n\t}\n\tif par.Node.Attr[`limit`] != nil {\n\t\tlimit = converter.StrToInt(par.Node.Attr[`limit`].(string))\n\t}\n\tif limit > consts.DBFindLimit {\n\t\tlimit = consts.DBFindLimit\n\t}\n\tif par.Node.Attr[`offset`] != nil {\n\t\toffset = fmt.Sprintf(` offset %d`, converter.StrToInt(par.Node.Attr[`offset`].(string)))\n\t}\n\n\tif par.Node.Attr[`prefix`] != nil {\n\t\tprefix = par.Node.Attr[`prefix`].(string)\n\t\tlimit = 1\n\t}\n\tstate = converter.StrToInt64(getVar(par.Workspace, `ecosystem_id`))\n\tif par.Node.Attr[\"cutoff\"] != nil {\n\t\tfor _, v := range strings.Split(par.Node.Attr[\"cutoff\"].(string), \",\") {\n\t\t\tcutoffColumns[v] = true\n\t\t}\n\t}\n\n\tsc := par.Workspace.SmartContract\n\ttblname := converter.ParseTable(strings.Trim(macro((*par.Pars)[`Name`], par.Workspace.Vars), `\"`), state)\n\ttblname = strings.ToLower(tblname)\n\n\tinColumns = ``\n\tif par.Node.Attr[`order`] != nil {\n\t\torder = macro(par.Node.Attr[`order`].(string), par.Workspace.Vars)\n\t\tif strings.HasPrefix(order, `[`) || strings.HasPrefix(order, `{`) {\n\t\t\tinColumns, _, err = ParseObject([]rune(order))\n\t\t\tif err != nil {\n\t\t\t\treturn err.Error()\n\t\t\t}\n\t\t} else {\n\t\t\tinColumns = order\n\t\t}\n\t}\n\torder, err = qb.GetOrder(tblname, inColumns, true)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\torder = ` order by ` + order\n\trows, err := sc.DbTransaction.GetAllColumnTypes(tblname)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting column types from db\")\n\t\treturn err.Error()\n\t}\n\tcolumnTypes := make(map[string]string, len(rows))\n\tfor _, row := range rows {\n\t\tcolumnTypes[row[columnNameKey]] = row[dataTypeKey]\n\t}\n\tcolumnNames := make([]string, 0)\n\n\tperm, err = sc.AccessTablePerm(tblname, `read`)\n\tif err != nil || sc.AccessColumns(tblname, &columns, false) != nil {\n\t\tlog.WithFields(log.Fields{\"table\": tblname, \"columns\": columns}).Error(\"ACCESS DENIED\")\n\t\treturn `Access denied`\n\t}\n\n\tif utils.StringInSlice(columns, `*`) {\n\t\tfor _, col := range rows {\n\t\t\tqueryColumns = append(queryColumns, col[columnNameKey])\n\t\t\tcolumnNames = append(columnNames, col[columnNameKey])\n\t\t}\n\t} else {\n\t\tif !utils.StringInSlice(columns, `id`) {\n\t\t\tcolumns = append(columns, `id`)\n\t\t}\n\t\tcolumnNames = make([]string, len(columns))\n\t\tcopy(columnNames, columns)\n\t\tqueryColumns = strings.Split(smart.PrepareColumns(columns), \",\")\n\t}\n\n\tfor i, col := range queryColumns {\n\t\tcol = strings.Trim(col, `\"`)\n\t\tswitch columnTypes[col] {\n\t\tcase \"bytea\":\n\t\t\textendedColumns[col] = columnTypeBlob\n\t\t\tqueryColumns[i] = dbfindExpressionBlob(col)\n\t\t\tbreak\n\t\tcase \"text\", \"varchar\", \"character varying\":\n\t\t\tif cutoffColumns[col] {\n\t\t\t\textendedColumns[col] = columnTypeLongText\n\t\t\t\tqueryColumns[i] = dbfindExpressionLongText(col)\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tfor i, field := range queryColumns {\n\t\tif !strings.ContainsAny(field, `:.>\"`) {\n\t\t\tqueryColumns[i] = `\"` + field + `\"`\n\t\t}\n\t}\n\tfor i, key := range columnNames {\n\t\tif strings.Contains(key, `->`) {\n\t\t\tcolumnNames[i] = strings.Replace(key, `->`, `.`, -1)\n\t\t}\n\t\tcolumnNames[i] = strings.TrimSpace(columnNames[i])\n\t}\n\tif par.Node.Attr[`countvar`] != nil {\n\t\tvar count int64\n\t\terr = sqldb.GetDB(nil).Table(tblname).Where(where).Count(&count).Error\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"selecting count from table in DBFind\")\n\t\t}\n\t\tcountStr := converter.Int64ToStr(count)\n\t\tpar.Node.Attr[`count`] = countStr\n\t\tsetVar(par.Workspace, par.Node.Attr[`countvar`].(string), countStr)\n\t\tdelete(par.Node.Attr, `countvar`)\n\t}\n\tif len(where) > 0 {\n\t\twhere = ` where ` + where\n\t}\n\tlist, err := sc.DbTransaction.GetAllTransaction(`select `+strings.Join(queryColumns, `, `)+` from \"`+tblname+`\"`+\n\t\twhere+order+offset, limit)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all from db\")\n\t\treturn err.Error()\n\t}\n\tdata := make([][]string, 0)\n\ttypes := make([]string, 0)\n\tlencol := 0\n\tdefcol := 0\n\tfor _, item := range list {\n\t\tif lencol == 0 {\n\t\t\tfor _, key := range columnNames {\n\t\t\t\tif v, ok := extendedColumns[key]; ok {\n\t\t\t\t\ttypes = append(types, v)\n\t\t\t\t} else {\n\t\t\t\t\ttypes = append(types, columnTypeText)\n\t\t\t\t}\n\t\t\t}\n\t\t\tdefcol = len(columnNames)\n\t\t\tif par.Node.Attr[`customs`] != nil {\n\t\t\t\tfor _, v := range par.Node.Attr[`customs`].([]string) {\n\t\t\t\t\tcolumnNames = append(columnNames, v)\n\t\t\t\t\ttypes = append(types, `tags`)\n\t\t\t\t}\n\t\t\t}\n\t\t\tlencol = len(columnNames)\n\t\t}\n\t\trow := make([]string, lencol)\n\t\tfor i, icol := range columnNames {\n\t\t\tvar ival string\n\t\t\tif i < defcol {\n\t\t\t\tival = item[icol]\n\t\t\t\tif ival == `NULL` {\n\t\t\t\t\tival = ``\n\t\t\t\t}\n\n\t\t\t\tswitch extendedColumns[icol] {\n\t\t\t\tcase columnTypeBlob:\n\t\t\t\t\tlink := &valueLink{id: item[\"id\"], column: icol, table: tblname, hash: ival, title: ival}\n\t\t\t\t\tival, err = link.marshal()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err.Error()\n\t\t\t\t\t}\n\t\t\t\t\titem[icol] = link.link()\n\t\t\t\t\tbreak\n\t\t\t\tcase columnTypeLongText:\n\t\t\t\t\tvar res []string\n\t\t\t\t\terr = json.Unmarshal([]byte(ival), &res)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"error\": err}).Error(\"unmarshalling long text params from JSON\")\n\t\t\t\t\t\treturn err.Error()\n\t\t\t\t\t}\n\t\t\t\t\tlink := &valueLink{id: item[\"id\"], column: icol, table: tblname, hash: res[1], title: res[0]}\n\t\t\t\t\tival, err = link.marshal()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err.Error()\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\troot := node{}\n\t\t\t\tfor key, val := range item {\n\t\t\t\t\t(*par.Workspace.Vars)[key] = Var{Value: val}\n\t\t\t\t}\n\t\t\t\tprocess(par.Node.Attr[`custombody`].([]string)[i-defcol], &root, par.Workspace)\n\t\t\t\tfor key := range item {\n\t\t\t\t\tdelete(*par.Workspace.Vars, key)\n\t\t\t\t}\n\t\t\t\tout, err := json.Marshal(root.Children)\n\t\t\t\tif err == nil {\n\t\t\t\t\tival = macro(string(out), mapToVar(item))\n\t\t\t\t} else {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marshalling root children to JSON\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tif par.Node.Attr[`prefix`] != nil {\n\t\t\t\tsetVar(par.Workspace, prefix+`_`+strings.Replace(icol, `.`, `_`, -1), ival)\n\t\t\t}\n\t\t\trow[i] = ival\n\t\t}\n\t\tdata = append(data, row)\n\t}\n\tif perm != nil && len(perm[`filter`]) > 0 {\n\t\tresult := make([]any, len(data))\n\t\tfor i, item := range data {\n\t\t\trow := make(map[string]string)\n\t\t\tfor j, col := range columnNames {\n\t\t\t\trow[col] = item[j]\n\t\t\t}\n\t\t\tresult[i] = reflect.ValueOf(row).Interface()\n\t\t}\n\t\tfltResult, err := sc.VM.EvalIf(perm[`filter`], uint32(sc.TxSmart.EcosystemID),\n\t\t\tmap[string]any{\n\t\t\t\t`data`:         result,\n\t\t\t\t`ecosystem_id`: sc.TxSmart.EcosystemID,\n\t\t\t\t`key_id`:       sc.TxSmart.KeyID, `sc`: sc,\n\t\t\t\t`block_time`: 0, `time`: sc.Timestamp})\n\t\tif err != nil || !fltResult {\n\t\t\treturn `Access denied`\n\t\t}\n\t\tfor i := range data {\n\t\t\tfor j, col := range columnNames {\n\t\t\t\tdata[i][j] = result[i].(map[string]string)[col]\n\t\t\t}\n\t\t}\n\t}\n\tsetAllAttr(par)\n\tdelete(par.Node.Attr, `customs`)\n\tdelete(par.Node.Attr, `custombody`)\n\tdelete(par.Node.Attr, `prefix`)\n\tpar.Node.Attr[`columns`] = &columnNames\n\tpar.Node.Attr[`types`] = &types\n\tpar.Node.Attr[`data`] = &data\n\tnewSource(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc compositeTag(par parFunc) string {\n\tsetAllAttr(par)\n\tif len((*par.Pars)[`Name`]) == 0 {\n\t\treturn ``\n\t}\n\tif par.Owner.Attr[`composites`] == nil {\n\t\tpar.Owner.Attr[`composites`] = make([]string, 0)\n\t\tpar.Owner.Attr[`compositedata`] = make([]string, 0)\n\t}\n\tpar.Owner.Attr[`composites`] = append(par.Owner.Attr[`composites`].([]string),\n\t\tmacro((*par.Pars)[`Name`], par.Workspace.Vars))\n\tpar.Owner.Attr[`compositedata`] = append(par.Owner.Attr[`compositedata`].([]string),\n\t\tmacro((*par.Pars)[`Data`], par.Workspace.Vars))\n\treturn ``\n}\n\nfunc errredirTag(par parFunc) string {\n\tsetAllAttr(par)\n\tif len((*par.Pars)[`ErrorID`]) == 0 {\n\t\treturn ``\n\t}\n\tif par.Owner.Attr[`errredirect`] == nil {\n\t\tpar.Owner.Attr[`errredirect`] = make(map[string]map[string]any)\n\t}\n\tpar.Owner.Attr[`errredirect`].(map[string]map[string]any)[(*par.Pars)[`ErrorID`]] =\n\t\tpar.Node.Attr\n\treturn ``\n}\n\nfunc popupTag(par parFunc) string {\n\tsetAllAttr(par)\n\n\twidth := converter.StrToInt((*par.Pars)[`Width`])\n\tif width < 1 || width > 100 {\n\t\treturn ``\n\t}\n\n\tpar.Owner.Attr[`popup`] = par.Node.Attr\n\treturn ``\n}\n\nfunc customTag(par parFunc) string {\n\tsetAllAttr(par)\n\tif len((*par.Pars)[`Column`]) == 0 || len((*par.Pars)[`Body`]) == 0 {\n\t\treturn ``\n\t}\n\tif par.Owner.Attr[`customs`] == nil {\n\t\tpar.Owner.Attr[`customs`] = make([]string, 0)\n\t\tpar.Owner.Attr[`custombody`] = make([]string, 0)\n\t}\n\tpar.Owner.Attr[`customs`] = append(par.Owner.Attr[`customs`].([]string), par.Node.Attr[`column`].(string))\n\tpar.Owner.Attr[`custombody`] = append(par.Owner.Attr[`custombody`].([]string), (*par.Pars)[`Body`])\n\treturn ``\n}\n\nfunc customTagFull(par parFunc) string {\n\tsetAllAttr(par)\n\tprocess((*par.Pars)[`Body`], par.Node, par.Workspace)\n\tpar.Owner.Tail = append(par.Owner.Tail, par.Node)\n\treturn ``\n}\n\nfunc tailTag(par parFunc) string {\n\tsetAllAttr(par)\n\tfor key, v := range par.Node.Attr {\n\t\tswitch v.(type) {\n\t\tcase string:\n\t\t\tpar.Owner.Attr[key] = macro(v.(string), par.Workspace.Vars)\n\t\tdefault:\n\t\t\tpar.Owner.Attr[key] = v\n\t\t}\n\t}\n\treturn ``\n}\n\nfunc showHideTag(par parFunc, action string) string {\n\tsetAllAttr(par)\n\tcond := par.Node.Attr[`condition`]\n\tif v, ok := cond.(string); ok {\n\t\tval := make(map[string]string)\n\t\titems := strings.Split(v, `,`)\n\t\tfor _, item := range items {\n\t\t\tlr := strings.SplitN(strings.TrimSpace(item), `=`, 2)\n\t\t\tkey := strings.TrimSpace(lr[0])\n\t\t\tif len(lr) == 2 {\n\t\t\t\tval[key] = macro(strings.TrimSpace(lr[1]), par.Workspace.Vars)\n\t\t\t} else {\n\t\t\t\tval[key] = ``\n\t\t\t}\n\t\t}\n\t\tif _, ok := par.Owner.Attr[action]; ok {\n\t\t\tpar.Owner.Attr[action] = append(par.Owner.Attr[action].([]map[string]string), val)\n\t\t} else {\n\t\t\tpar.Owner.Attr[action] = []map[string]string{val}\n\t\t}\n\t}\n\treturn ``\n}\n\nfunc showTag(par parFunc) string {\n\treturn showHideTag(par, `show`)\n}\n\nfunc hideTag(par parFunc) string {\n\treturn showHideTag(par, `hide`)\n}\n\nfunc includeTag(par parFunc) string {\n\tif len((*par.Pars)[`Name`]) >= 0 && len(getVar(par.Workspace, `_include`)) < 5 {\n\t\tbi := &sqldb.Snippet{}\n\t\tname := macro((*par.Pars)[`Name`], par.Workspace.Vars)\n\t\tecosystem, tblname := converter.ParseName(name)\n\t\tprefix := getVar(par.Workspace, `ecosystem_id`)\n\t\tif ecosystem != 0 {\n\t\t\tprefix = converter.Int64ToStr(ecosystem)\n\t\t\tname = tblname\n\t\t}\n\t\tbi.SetTablePrefix(prefix)\n\t\tfound, err := bi.Get(name)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting snippet by name\")\n\t\t\treturn err.Error()\n\t\t}\n\t\tif !found {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.NotFound, \"name\": (*par.Pars)[`Name`]}).Error(\"include snippet not found\")\n\t\t\treturn fmt.Sprintf(\"Inlcude %s has not been found\", (*par.Pars)[`Name`])\n\t\t}\n\t\tif len(bi.Value) > 0 {\n\t\t\troot := node{}\n\t\t\tsetVar(par.Workspace, `_include`, getVar(par.Workspace, `_include`)+`1`)\n\t\t\tprocess(bi.Value, &root, par.Workspace)\n\t\t\tinclude := getVar(par.Workspace, `_include`)\n\t\t\tsetVar(par.Workspace, `_include`, include[:len(include)-1])\n\t\t\tfor _, item := range root.Children {\n\t\t\t\tpar.Owner.Children = append(par.Owner.Children, item)\n\t\t\t}\n\t\t}\n\t}\n\treturn ``\n}\n\nfunc setvarTag(par parFunc) string {\n\tif len((*par.Pars)[`Name`]) > 0 {\n\t\tif strings.ContainsAny((*par.Pars)[`Value`], `({`) {\n\t\t\t(*par.Pars)[`Value`] = processToText(par, (*par.Pars)[`Value`])\n\t\t}\n\t\tsetVar(par.Workspace, (*par.Pars)[`Name`], macroReplace((*par.Pars)[`Value`], par.Workspace.Vars))\n\t}\n\treturn ``\n}\n\nfunc varasisTag(par parFunc) string {\n\tkey := (*par.Pars)[`Name`]\n\tif len(key) > 0 {\n\t\tvalue := (*par.Pars)[`Value`]\n\t\tif strings.HasPrefix(value, `#`) {\n\t\t\tif v, ok := (*par.Workspace.Vars)[strings.Trim(value, `#`)]; ok {\n\t\t\t\tvalue = v.Value\n\t\t\t}\n\t\t} else if v, ok := (*par.Workspace.Vars)[value]; ok {\n\t\t\tvalue = v.Value\n\t\t}\n\t\t(*par.Workspace.Vars)[key] = Var{Value: value, AsIs: true}\n\t}\n\treturn ``\n}\n\nfunc getvarTag(par parFunc) string {\n\tif len((*par.Pars)[`Name`]) > 0 {\n\t\treturn macro(getVar(par.Workspace, (*par.Pars)[`Name`]), par.Workspace.Vars)\n\t}\n\treturn ``\n}\n\nfunc tableTag(par parFunc) string {\n\tdefaultTag(par)\n\tdefaultTail(par, `table`)\n\tif len((*par.Pars)[`Columns`]) > 0 {\n\t\timap := make([]map[string]string, 0)\n\t\tfor _, v := range strings.Split((*par.Pars)[`Columns`], `,`) {\n\t\t\tv = macro(strings.TrimSpace(v), par.Workspace.Vars)\n\t\t\tif off := strings.IndexByte(v, '='); off == -1 {\n\t\t\t\timap = append(imap, map[string]string{`Title`: v, `Name`: v})\n\t\t\t} else {\n\t\t\t\timap = append(imap, map[string]string{`Title`: strings.TrimSpace(v[:off]), `Name`: strings.TrimSpace(v[off+1:])})\n\t\t\t}\n\t\t}\n\t\tif len(imap) > 0 {\n\t\t\tpar.Node.Attr[`columns`] = imap\n\t\t}\n\t}\n\treturn ``\n}\n\nfunc validateTag(par parFunc) string {\n\tsetAllAttr(par)\n\tpar.Owner.Attr[`validate`] = par.Node.Attr\n\treturn ``\n}\n\nfunc validateFull(par parFunc) string {\n\tsetAllAttr(par)\n\tpar.Owner.Tail = append(par.Owner.Tail, par.Node)\n\treturn ``\n}\n\nfunc defaultTail(par parFunc, tag string) {\n\tif par.Tails != nil {\n\t\tfor _, v := range *par.Tails {\n\t\t\tname := (*v)[len(*v)-1]\n\t\t\tcurFunc := tails[tag].Tails[string(name)].tplFunc\n\t\t\tpars := (*v)[:len(*v)-1]\n\t\t\tcallFunc(&curFunc, par.Node, par.Workspace, &pars, nil)\n\t\t}\n\t}\n}\n\nfunc defaultTailTag(par parFunc) string {\n\tdefaultTag(par)\n\tdefaultTail(par, par.Node.Tag)\n\treturn ``\n}\n\nfunc buttonTag(par parFunc) string {\n\tdefaultTag(par)\n\tdefaultTail(par, `button`)\n\tdefer func() {\n\t\tdelete(par.Node.Attr, `composites`)\n\t\tdelete(par.Node.Attr, `compositedata`)\n\t}()\n\tif par.Node.Attr[`composites`] != nil {\n\t\tcomposites := make([]Composite, 0)\n\t\tfor i, name := range par.Node.Attr[`composites`].([]string) {\n\t\t\tvar data any\n\t\t\tinput := par.Node.Attr[`compositedata`].([]string)[i]\n\t\t\tif len(input) > 0 {\n\t\t\t\tif err := json.Unmarshal([]byte(input), &data); err != nil {\n\t\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.JSONUnmarshallError, \"source\": input}).Error(\"on button tag unmarshaling content\")\n\t\t\t\t\treturn err.Error()\n\t\t\t\t}\n\t\t\t}\n\t\t\tcomposites = append(composites, Composite{Name: name, Data: data})\n\t\t}\n\t\tpar.Node.Attr[`composite`] = &composites\n\t}\n\treturn ``\n}\n\nfunc ifTag(par parFunc) string {\n\tcond := ifValue((*par.Pars)[`Condition`], par.Workspace)\n\tif cond {\n\t\tprocess((*par.Pars)[`Body`], par.Node, par.Workspace)\n\t\tfor _, item := range par.Node.Children {\n\t\t\tpar.Owner.Children = append(par.Owner.Children, item)\n\t\t}\n\t}\n\tif !cond && par.Tails != nil {\n\t\tfor _, v := range *par.Tails {\n\t\t\tname := (*v)[len(*v)-1]\n\t\t\tcurFunc := tails[`if`].Tails[string(name)].tplFunc\n\t\t\tpars := (*v)[:len(*v)-1]\n\t\t\tcallFunc(&curFunc, par.Owner, par.Workspace, &pars, nil)\n\t\t\tif getVar(par.Workspace, `_cond`) == `1` {\n\t\t\t\tsetVar(par.Workspace, `_cond`, `0`)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn ``\n}\n\nfunc ifFull(par parFunc) string {\n\tsetAttr(par, `Condition`)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\tif par.Tails != nil {\n\t\tfor _, v := range *par.Tails {\n\t\t\tname := (*v)[len(*v)-1]\n\t\t\tcurFunc := tails[`if`].Tails[string(name)].tplFunc\n\t\t\tpars := (*v)[:len(*v)-1]\n\t\t\tcallFunc(&curFunc, par.Node, par.Workspace, &pars, nil)\n\t\t}\n\t}\n\treturn ``\n}\n\nfunc elseifTag(par parFunc) string {\n\tcond := ifValue((*par.Pars)[`Condition`], par.Workspace)\n\tif cond {\n\t\tprocess((*par.Pars)[`Body`], par.Node, par.Workspace)\n\t\tfor _, item := range par.Node.Children {\n\t\t\tpar.Owner.Children = append(par.Owner.Children, item)\n\t\t}\n\t\tsetVar(par.Workspace, `_cond`, `1`)\n\t}\n\treturn ``\n}\n\nfunc elseifFull(par parFunc) string {\n\tsetAttr(par, `Condition`)\n\tpar.Owner.Tail = append(par.Owner.Tail, par.Node)\n\treturn ``\n}\n\nfunc elseTag(par parFunc) string {\n\tfor _, item := range par.Node.Children {\n\t\tpar.Owner.Children = append(par.Owner.Children, item)\n\t}\n\treturn ``\n}\n\nfunc elseFull(par parFunc) string {\n\tpar.Owner.Tail = append(par.Owner.Tail, par.Node)\n\treturn ``\n}\n\nfunc dateTimeTag(par parFunc) string {\n\tdatetime := par.ParamWithMacros(\"DateTime\")\n\tif len(datetime) == 0 || datetime[0] < '0' || datetime[0] > '9' {\n\t\treturn ``\n\t}\n\tvalue := datetime\n\tdefTime := `1970-01-01T00:00:00`\n\tlenTime := len(datetime)\n\tif lenTime < len(defTime) {\n\t\tdatetime += defTime[lenTime:]\n\t}\n\titime, err := time.Parse(`2006-01-02T15:04:05`, strings.Replace(datetime[:19], ` `, `T`, -1))\n\tif err != nil {\n\t\tunix := converter.StrToInt64(value)\n\t\tif unix > 0 {\n\t\t\titime = time.Unix(unix, 0)\n\t\t} else {\n\t\t\treturn err.Error()\n\t\t}\n\t}\n\tformat := par.ParamWithMacros(\"Format\")\n\tif len(format) == 0 {\n\t\tformat, _ = language.LangText(nil, `timeformat`,\n\t\t\tconverter.StrToInt(getVar(par.Workspace, `ecosystem_id`)), getVar(par.Workspace, `lang`))\n\t\tif format == `timeformat` {\n\t\t\tformat = `2006-01-02 15:04:05`\n\t\t}\n\t} else {\n\t\tformat = macro(format, par.Workspace.Vars)\n\t}\n\tformat = strings.Replace(format, `YYYY`, `2006`, -1)\n\tformat = strings.Replace(format, `YY`, `06`, -1)\n\tformat = strings.Replace(format, `MM`, `01`, -1)\n\tformat = strings.Replace(format, `DD`, `02`, -1)\n\tformat = strings.Replace(format, `HH`, `15`, -1)\n\tformat = strings.Replace(format, `MI`, `04`, -1)\n\tformat = strings.Replace(format, `SS`, `05`, -1)\n\n\tlocationName := par.ParamWithMacros(\"Location\")\n\tif len(locationName) > 0 {\n\t\tloc, err := time.LoadLocation(locationName)\n\t\tif err != nil {\n\t\t\treturn err.Error()\n\t\t}\n\t\titime = itime.In(loc)\n\t}\n\n\treturn itime.Format(format)\n}\n\nfunc cmpTimeTag(par parFunc) string {\n\tprepare := func(val string) string {\n\t\tval = strings.Replace(macro(val, par.Workspace.Vars), `T`, ` `, -1)\n\t\tif len(val) > 19 {\n\t\t\tval = val[:19]\n\t\t}\n\t\treturn val\n\t}\n\tleft := prepare((*par.Pars)[`Time1`])\n\tright := prepare((*par.Pars)[`Time2`])\n\tif left == right {\n\t\treturn `0`\n\t}\n\tif left < right {\n\t\treturn `-1`\n\t}\n\treturn `1`\n}\n\ntype byFirst [][]string\n\nfunc (s byFirst) Len() int {\n\treturn len(s)\n}\nfunc (s byFirst) Swap(i, j int) {\n\ts[i], s[j] = s[j], s[i]\n}\nfunc (s byFirst) Less(i, j int) bool {\n\treturn strings.Compare(s[i][0], s[j][0]) < 0\n}\n\nfunc jsontosourceTag(par parFunc) string {\n\tsetAllAttr(par)\n\tvar prefix string\n\tif par.Node.Attr[`prefix`] != nil {\n\t\tprefix = par.Node.Attr[`prefix`].(string) + `_`\n\t}\n\tdata := make([][]string, 0, 16)\n\tcols := []string{prefix + `key`, prefix + `value`}\n\ttypes := []string{`text`, `text`}\n\tvar out map[string]any\n\tdataVal := macro((*par.Pars)[`Data`], par.Workspace.Vars)\n\tif len(dataVal) > 0 {\n\t\tjson.Unmarshal([]byte(macro((*par.Pars)[`Data`], par.Workspace.Vars)), &out)\n\t}\n\tfor key, item := range out {\n\t\tif item == nil {\n\t\t\titem = ``\n\t\t}\n\t\tvar value string\n\t\tswitch v := item.(type) {\n\t\tcase map[string]any:\n\t\t\tvar keys, values []string\n\t\t\tfor k := range v {\n\t\t\t\tkeys = append(keys, k)\n\t\t\t}\n\t\t\tsort.Strings(keys)\n\t\t\tfor _, k := range keys {\n\t\t\t\tvalues = append(values, fmt.Sprintf(`%q:%q`, k, v[k]))\n\t\t\t}\n\t\t\tvalue = `{` + strings.Join(values, \",\\r\\n\") + `}`\n\t\tdefault:\n\t\t\tvalue = fmt.Sprint(item)\n\t\t}\n\t\tdata = append(data, []string{key, value})\n\t}\n\tsort.Sort(byFirst(data))\n\tsetAllAttr(par)\n\tpar.Node.Attr[`columns`] = &cols\n\tpar.Node.Attr[`types`] = &types\n\tpar.Node.Attr[`data`] = &data\n\tnewSource(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc arraytosourceTag(par parFunc) string {\n\tsetAllAttr(par)\n\n\tvar prefix string\n\tif par.Node.Attr[`prefix`] != nil {\n\t\tprefix = par.Node.Attr[`prefix`].(string) + `_`\n\t}\n\n\tdata := make([][]string, 0, 16)\n\tcols := []string{prefix + `key`, prefix + `value`}\n\ttypes := []string{`text`, `text`}\n\tfor key, item := range splitArray([]rune(macro((*par.Pars)[`Data`], par.Workspace.Vars))) {\n\t\tdata = append(data, []string{fmt.Sprint(key), item})\n\t}\n\tsetAllAttr(par)\n\tpar.Node.Attr[`columns`] = &cols\n\tpar.Node.Attr[`types`] = &types\n\tpar.Node.Attr[`data`] = &data\n\tnewSource(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc chartTag(par parFunc) string {\n\tdefaultTag(par)\n\tdefaultTail(par, \"chart\")\n\n\tif len((*par.Pars)[\"Colors\"]) > 0 {\n\t\tcolors := strings.Split(macro((*par.Pars)[\"Colors\"], par.Workspace.Vars), \",\")\n\t\tfor i, v := range colors {\n\t\t\tcolors[i] = strings.TrimSpace(v)\n\t\t}\n\t\tpar.Node.Attr[\"colors\"] = colors\n\t}\n\n\treturn \"\"\n}\n\nfunc rangeTag(par parFunc) string {\n\tsetAllAttr(par)\n\tstep := int64(1)\n\tdata := make([][]string, 0, 32)\n\tfrom := converter.StrToInt64(macro((*par.Pars)[\"From\"], par.Workspace.Vars))\n\tto := converter.StrToInt64(macro((*par.Pars)[\"To\"], par.Workspace.Vars))\n\tif len((*par.Pars)[\"Step\"]) > 0 {\n\t\tstep = converter.StrToInt64(macro((*par.Pars)[\"Step\"], par.Workspace.Vars))\n\t}\n\tif step > 0 && from < to {\n\t\tfor i := from; i < to; i += step {\n\t\t\tdata = append(data, []string{converter.Int64ToStr(i)})\n\t\t}\n\t} else if step < 0 && from > to {\n\t\tfor i := from; i > to; i += step {\n\t\t\tdata = append(data, []string{converter.Int64ToStr(i)})\n\t\t}\n\t}\n\tdelete(par.Node.Attr, `from`)\n\tdelete(par.Node.Attr, `to`)\n\tdelete(par.Node.Attr, `step`)\n\tpar.Node.Attr[`columns`] = &[]string{\"id\"}\n\tpar.Node.Attr[`data`] = &data\n\tnewSource(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n\nfunc imageTag(par parFunc) string {\n\t(*par.Pars)[\"Src\"] = parseArg((*par.Pars)[\"Src\"], par.Workspace)\n\tdefaultTag(par)\n\tdefaultTail(par, par.Node.Tag)\n\treturn ``\n}\n\nfunc binaryTag(par parFunc) string {\n\tvar ecosystemID string\n\n\tdefaultTail(par, `binary`)\n\tif par.Node.Attr[`ecosystem`] != nil {\n\t\tecosystemID = par.Node.Attr[`ecosystem`].(string)\n\t} else {\n\t\tecosystemID = getVar(par.Workspace, `ecosystem_id`)\n\t}\n\tbinary := &sqldb.Binary{}\n\tbinary.SetTablePrefix(ecosystemID)\n\n\tvar (\n\t\tok  bool\n\t\terr error\n\t)\n\n\tif par.Node.Attr[\"id\"] != nil {\n\t\tok, err = binary.GetByID(converter.StrToInt64(macro(par.Node.Attr[\"id\"].(string), par.Workspace.Vars)))\n\t} else {\n\t\tok, err = binary.Get(\n\t\t\tconverter.StrToInt64(par.ParamWithMacros(\"AppID\")),\n\t\t\tpar.ParamWithMacros(\"Account\"),\n\t\t\tpar.ParamWithMacros(\"Name\"),\n\t\t)\n\t}\n\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting record from db\")\n\t\treturn err.Error()\n\t}\n\n\tif ok {\n\t\treturn binary.Link()\n\t}\n\n\treturn \"\"\n}\n\nfunc columntypeTag(par parFunc) string {\n\tif len((*par.Pars)[\"Table\"]) > 0 && len((*par.Pars)[\"Column\"]) > 0 {\n\t\ttableName := macro((*par.Pars)[`Table`], par.Workspace.Vars)\n\t\tcolumnName := macro((*par.Pars)[`Column`], par.Workspace.Vars)\n\t\ttblname := qb.GetTableName(par.Workspace.SmartContract.TxSmart.EcosystemID, tableName)\n\t\tcolType, err := par.Workspace.SmartContract.DbTransaction.GetColumnType(tblname, columnName)\n\t\tif err == nil {\n\t\t\treturn colType\n\t\t}\n\t\treturn err.Error()\n\t}\n\treturn ``\n}\n\nfunc getHistoryTag(par parFunc) string {\n\tsetAllAttr(par)\n\tvar rollID int64\n\tif len((*par.Pars)[\"RollbackId\"]) > 0 {\n\t\trollID = converter.StrToInt64(macro((*par.Pars)[`RollbackId`], par.Workspace.Vars))\n\t}\n\tif len((*par.Pars)[\"Name\"]) == 0 {\n\t\treturn ``\n\t}\n\ttable := macro((*par.Pars)[\"Name\"], par.Workspace.Vars)\n\tlist, err := smart.GetHistoryRaw(nil, converter.StrToInt64(getVar(par.Workspace, `ecosystem_id`)),\n\t\ttable, converter.StrToInt64(macro((*par.Pars)[`Id`], par.Workspace.Vars)), rollID)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\tcolsList, err := par.Workspace.SmartContract.DbTransaction.GetAllColumnTypes(getVar(par.Workspace, `ecosystem_id`) + \"_\" + table)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting column types from db\")\n\t\treturn err.Error()\n\t}\n\n\tcols := make([]string, 0, len(colsList))\n\ttypesCol := make([]string, 0, len(colsList))\n\tfor _, v := range colsList {\n\n\t\tcols = append(cols, v[columnNameKey])\n\t\ttypesCol = append(typesCol, `text`)\n\t}\n\n\tdata := make([][]string, 0)\n\tif len(list) > 0 {\n\t\tfor i := range list {\n\t\t\titem := list[i].(*types.Map)\n\t\t\titems := make([]string, len(cols))\n\t\t\tfor ind, key := range cols {\n\t\t\t\tvar val string\n\t\t\t\tif v, found := item.Get(key); found {\n\t\t\t\t\tval = v.(string)\n\t\t\t\t}\n\t\t\t\tif val == `NULL` {\n\t\t\t\t\tval = ``\n\t\t\t\t}\n\t\t\t\titems[ind] = val\n\t\t\t}\n\t\t\tdata = append(data, items)\n\t\t}\n\t}\n\tpar.Node.Attr[`columns`] = &cols\n\tpar.Node.Attr[`types`] = &typesCol\n\tpar.Node.Attr[`data`] = &data\n\tnewSource(par)\n\tpar.Owner.Children = append(par.Owner.Children, par.Node)\n\treturn ``\n}\n"
  },
  {
    "path": "packages/template/template.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage template\n\nimport (\n\t\"encoding/json\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/language\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\ttagText = `text`\n\tmaxDeep = 16\n)\n\ntype node struct {\n\tTag      string         `json:\"tag\"`\n\tAttr     map[string]any `json:\"attr,omitempty\"`\n\tText     string         `json:\"text,omitempty\"`\n\tChildren []*node        `json:\"children,omitempty\"`\n\tTail     []*node        `json:\"tail,omitempty\"`\n}\n\n// Source describes dbfind or data source\ntype Source struct {\n\tColumns *[]string\n\tData    *[][]string\n}\n\n// Var stores value and additional parameter of variable\ntype Var struct {\n\tValue string\n\tAsIs  bool\n}\n\n// Workspace represents a workspace of executable template\ntype Workspace struct {\n\tSources       *map[string]Source\n\tVars          *map[string]Var\n\tSmartContract *smart.SmartContract\n\tTimeout       *bool\n}\n\n// SetSource sets source to workspace\nfunc (w *Workspace) SetSource(name string, source *Source) {\n\tif w.Sources == nil {\n\t\tsources := make(map[string]Source)\n\t\tw.Sources = &sources\n\t}\n\t(*w.Sources)[name] = *source\n}\n\ntype parFunc struct {\n\tOwner     *node\n\tNode      *node\n\tWorkspace *Workspace\n\tPars      *map[string]string\n\tRawPars   *map[string]string\n\tTails     *[]*[][]rune\n}\n\nfunc (p *parFunc) Param(key string) string {\n\treturn (*p.Pars)[key]\n}\n\nfunc (p *parFunc) ParamWithMacros(key string) string {\n\tv := p.Param(key)\n\treturn macro(v, p.Workspace.Vars)\n}\n\ntype nodeFunc func(par parFunc) string\n\ntype tplFunc struct {\n\tFunc   nodeFunc // process function\n\tFull   nodeFunc // full process function\n\tTag    string   // HTML tag\n\tParams string   // names of parameters\n}\n\ntype tailInfo struct {\n\ttplFunc\n\tLast bool\n}\n\ntype forTails struct {\n\tTails map[string]tailInfo\n}\n\nfunc newSource(par parFunc) {\n\tif par.Node.Attr[`source`] == nil {\n\t\treturn\n\t}\n\tpar.Workspace.SetSource(par.Node.Attr[`source`].(string), &Source{\n\t\tColumns: par.Node.Attr[`columns`].(*[]string),\n\t\tData:    par.Node.Attr[`data`].(*[][]string),\n\t})\n}\n\nfunc setAttr(par parFunc, name string) {\n\tif len((*par.Pars)[name]) > 0 {\n\t\tpar.Node.Attr[strings.ToLower(name)] = (*par.Pars)[name]\n\t}\n}\n\nfunc setAllAttr(par parFunc) {\n\tfor key, v := range *par.Pars {\n\t\tif key == `Params` || key == `PageParams` {\n\t\t\timap := make(map[string]any)\n\t\t\tre := regexp.MustCompile(`(?is)(.*)\\((.*)\\)`)\n\t\t\tparList := make([]string, 0, 10)\n\t\t\tcurPar := make([]rune, 0, 256)\n\t\t\tstack := make([]rune, 0, 256)\n\t\t\tfor _, ch := range v {\n\t\t\t\tswitch ch {\n\t\t\t\tcase '\"':\n\t\t\t\t\tif len(stack) > 0 && stack[len(stack)-1] == '\"' {\n\t\t\t\t\t\tstack = stack[:len(stack)-1]\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstack = append(stack, '\"')\n\t\t\t\t\t}\n\t\t\t\tcase '(':\n\t\t\t\t\tstack = append(stack, ')')\n\t\t\t\tcase '{':\n\t\t\t\t\tstack = append(stack, '}')\n\t\t\t\tcase '[':\n\t\t\t\t\tstack = append(stack, ']')\n\t\t\t\tcase ')', '}', ']':\n\t\t\t\t\tif len(stack) > 0 && stack[len(stack)-1] == ch {\n\t\t\t\t\t\tstack = stack[:len(stack)-1]\n\t\t\t\t\t}\n\t\t\t\tcase ',':\n\t\t\t\t\tif len(stack) == 0 {\n\t\t\t\t\t\tparList = append(parList, string(curPar))\n\t\t\t\t\t\tcurPar = curPar[:0]\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurPar = append(curPar, ch)\n\t\t\t}\n\t\t\tif len(curPar) > 0 {\n\t\t\t\tparList = append(parList, string(curPar))\n\t\t\t}\n\t\t\tfor _, parval := range parList {\n\t\t\t\tparval = strings.TrimSpace(parval)\n\t\t\t\tif len(parval) > 0 {\n\t\t\t\t\tif off := strings.IndexByte(parval, '='); off == -1 {\n\t\t\t\t\t\timap[parval] = map[string]any{\n\t\t\t\t\t\t\t`type`: `text`, `text`: parval}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval := strings.TrimSpace(parval[off+1:])\n\t\t\t\t\t\tif ret := re.FindStringSubmatch(val); len(ret) == 3 {\n\t\t\t\t\t\t\tplist := strings.Split(ret[2], `,`)\n\t\t\t\t\t\t\tfor i, ilist := range plist {\n\t\t\t\t\t\t\t\tplist[i] = strings.TrimSpace(ilist)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\timap[strings.TrimSpace(parval[:off])] = map[string]any{\n\t\t\t\t\t\t\t\t`type`: ret[1], `params`: plist}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\timap[strings.TrimSpace(parval[:off])] = map[string]any{\n\t\t\t\t\t\t\t\t`type`: `text`, `text`: val}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(imap) > 0 {\n\t\t\t\tpar.Node.Attr[strings.ToLower(key)] = imap\n\t\t\t}\n\t\t} else if key != `Body` && (key != `Data` || getVar(par.Workspace, `_full`) == `1`) &&\n\t\t\tlen(v) > 0 {\n\t\t\tpar.Node.Attr[strings.ToLower(key)] = v\n\t\t}\n\t}\n\tfor key := range *par.Pars {\n\t\tif len(key) == 0 || key[0] != '@' {\n\t\t\tcontinue\n\t\t}\n\n\t\tkey = strings.ToLower(key[1:])\n\t\tif par.Node.Attr[key] == nil {\n\t\t\tcontinue\n\t\t}\n\t\tpar.Node.Attr[key] = processToText(par, par.Node.Attr[key].(string))\n\t}\n}\n\nfunc processToText(par parFunc, input string) (out string) {\n\troot := node{}\n\tprocess(input, &root, par.Workspace)\n\tfor _, item := range root.Children {\n\t\tif item.Tag == `text` {\n\t\t\tout += item.Text\n\t\t}\n\t}\n\treturn\n}\n\nfunc ifValue(val string, workspace *Workspace) bool {\n\tvar sep string\n\n\tval = parseArg(val, workspace)\n\n\tif strings.Index(val, `;base64`) < 0 {\n\t\tfor _, item := range []string{`==`, `!=`, `<=`, `>=`, `<`, `>`} {\n\t\t\tif strings.Index(val, item) >= 0 {\n\t\t\t\tsep = item\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tcond := []string{val}\n\tif len(sep) > 0 {\n\t\tcond = strings.SplitN(val, sep, 2)\n\t\tcond[0], cond[1] = macro(strings.Trim(strings.TrimSpace(cond[0]), `\"`), workspace.Vars),\n\t\t\tmacro(strings.Trim(strings.TrimSpace(cond[1]), `\"`), workspace.Vars)\n\t} else {\n\t\tval = macro(val, workspace.Vars)\n\t}\n\tswitch sep {\n\tcase ``:\n\t\treturn len(val) > 0 && val != `0` && val != `false`\n\tcase `==`:\n\t\treturn len(cond) == 2 && strings.TrimSpace(cond[0]) == strings.TrimSpace(cond[1])\n\tcase `!=`:\n\t\treturn len(cond) == 2 && strings.TrimSpace(cond[0]) != strings.TrimSpace(cond[1])\n\tcase `>`, `<`, `<=`, `>=`:\n\t\tret0, _ := decimal.NewFromString(strings.TrimSpace(cond[0]))\n\t\tret1, _ := decimal.NewFromString(strings.TrimSpace(cond[1]))\n\t\tif len(cond) == 2 {\n\t\t\tvar bin bool\n\t\t\tif sep == `>` || sep == `<=` {\n\t\t\t\tbin = ret0.Cmp(ret1) > 0\n\t\t\t} else {\n\t\t\t\tbin = ret0.Cmp(ret1) < 0\n\t\t\t}\n\t\t\tif sep == `<=` || sep == `>=` {\n\t\t\t\tbin = !bin\n\t\t\t}\n\t\t\treturn bin\n\t\t}\n\t}\n\treturn false\n}\n\nfunc replace(input string, level *[]string, vars *map[string]Var) string {\n\tif len(input) == 0 {\n\t\treturn input\n\t}\n\tresult := make([]rune, 0, utf8.RuneCountInString(input))\n\tisName := false\n\tname := make([]rune, 0, 128)\n\tsyschar := '#'\n\tclearname := func() {\n\t\tresult = append(append(result, syschar), name...)\n\t\tisName = false\n\t\tname = name[:0]\n\t}\n\tfor _, r := range input {\n\t\tif r != syschar {\n\t\t\tif isName {\n\t\t\t\tname = append(name, r)\n\t\t\t\tif len(name) > 64 || r <= ' ' {\n\t\t\t\t\tclearname()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult = append(result, r)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif isName {\n\t\t\tif varValue, ok := (*vars)[string(name)]; ok {\n\t\t\t\tvalue := varValue.Value\n\t\t\t\tvar loop bool\n\t\t\t\tif len(*level) < maxDeep {\n\t\t\t\t\tfor _, item := range *level {\n\t\t\t\t\t\tif item == string(name) {\n\t\t\t\t\t\t\tloop = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tloop = true\n\t\t\t\t}\n\t\t\t\tif !loop {\n\t\t\t\t\tif !varValue.AsIs {\n\t\t\t\t\t\t*level = append(*level, string(name))\n\t\t\t\t\t\tvalue = replace(value, level, vars)\n\t\t\t\t\t\t*level = (*level)[:len(*level)-1]\n\t\t\t\t\t}\n\t\t\t\t\tresult = append(result, []rune(value)...)\n\t\t\t\t} else {\n\t\t\t\t\tresult = append(append(result, syschar), append(name, syschar)...)\n\t\t\t\t}\n\t\t\t}\n\t\t\tisName = false\n\t\t\tname = name[:0]\n\t\t} else {\n\t\t\tisName = true\n\t\t}\n\t}\n\tif isName {\n\t\tresult = append(append(result, syschar), name...)\n\t}\n\treturn string(result)\n}\n\nfunc macro(input string, vars *map[string]Var) string {\n\tif (*vars)[`_full`].Value == `1` || strings.IndexByte(input, '#') == -1 {\n\t\treturn input\n\t}\n\treturn macroReplace(input, vars)\n}\n\nfunc macroReplace(input string, vars *map[string]Var) string {\n\tlevel := make([]string, 0, maxDeep)\n\treturn replace(input, &level, vars)\n}\n\nfunc appendText(owner *node, text string) {\n\tif len(strings.TrimSpace(text)) == 0 {\n\t\treturn\n\t}\n\tif len(text) > 0 {\n\t\towner.Children = append(owner.Children, &node{Tag: tagText, Text: text})\n\t}\n}\n\nfunc callFunc(curFunc *tplFunc, owner *node, workspace *Workspace, params *[][]rune, tailpars *[]*[][]rune) {\n\tvar (\n\t\tout     string\n\t\tcurNode node\n\t)\n\tpars := make(map[string]string)\n\tparFunc := parFunc{\n\t\tWorkspace: workspace,\n\t}\n\tif *workspace.Timeout {\n\t\treturn\n\t}\n\ttrim := func(input string, quotes bool) string {\n\t\tresult := strings.Trim(input, \"\\t\\r\\n \")\n\t\tif quotes && len(result) > 0 {\n\t\t\tfor _, ch := range \"\\\"`\" {\n\t\t\t\tif rune(result[0]) == ch {\n\t\t\t\t\tresult = strings.Trim(result, string([]rune{ch}))\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\tif curFunc.Params == `*` {\n\t\tfor i, v := range *params {\n\t\t\tval := strings.TrimSpace(string(v))\n\t\t\toff := strings.IndexByte(val, ':')\n\t\t\tif off != -1 {\n\t\t\t\tpars[val[:off]] = macro(trim(val[off+1:], true), workspace.Vars)\n\t\t\t} else {\n\t\t\t\tpars[strconv.Itoa(i)] = val\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor i, v := range strings.Split(curFunc.Params, `,`) {\n\t\t\tif i < len(*params) {\n\t\t\t\tval := strings.TrimSpace(string((*params)[i]))\n\t\t\t\toff := strings.IndexByte(val, ':')\n\t\t\t\tif off != -1 && strings.Contains(curFunc.Params, `#`+val[:off]) {\n\t\t\t\t\tpars[`#`+val[:off]] = trim(val[off+1:], val[:off] != `Data`)\n\t\t\t\t} else if off != -1 && strings.Contains(curFunc.Params, val[:off]) {\n\t\t\t\t\tpars[val[:off]] = trim(val[off+1:], val[:off] != `Data`)\n\t\t\t\t} else {\n\t\t\t\t\tpars[v] = val\n\t\t\t\t}\n\t\t\t} else if _, ok := pars[v]; !ok {\n\t\t\t\tpars[v] = ``\n\t\t\t}\n\t\t}\n\t}\n\tstate := int(converter.StrToInt64(getVar(workspace, `ecosystem_id`)))\n\tif getVar(workspace, `_full`) != `1` {\n\t\tfor i, v := range pars {\n\t\t\tpars[i] = language.LangMacro(v, state, getVar(workspace, `lang`))\n\t\t\tif pars[i] != v {\n\t\t\t\tif parFunc.RawPars == nil {\n\t\t\t\t\trawpars := make(map[string]string)\n\t\t\t\t\tparFunc.RawPars = &rawpars\n\t\t\t\t}\n\t\t\t\t(*parFunc.RawPars)[i] = v\n\t\t\t}\n\t\t}\n\t}\n\tif len(curFunc.Tag) > 0 {\n\t\tcurNode.Tag = curFunc.Tag\n\t\tcurNode.Attr = make(map[string]any)\n\t\tif len(pars[`Body`]) > 0 && curFunc.Tag != `custom` {\n\t\t\tif (curFunc.Tag != `if` && curFunc.Tag != `elseif`) || getVar(workspace, `_full`) == `1` {\n\t\t\t\tprocess(pars[`Body`], &curNode, workspace)\n\t\t\t}\n\t\t}\n\t\tparFunc.Owner = owner\n\t\tparFunc.Node = &curNode\n\t\tparFunc.Tails = tailpars\n\t}\n\tif *workspace.Timeout {\n\t\treturn\n\t}\n\tparFunc.Pars = &pars\n\tif getVar(workspace, `_full`) == `1` {\n\t\tout = curFunc.Full(parFunc)\n\t} else {\n\t\tout = curFunc.Func(parFunc)\n\t}\n\tfor key, v := range parFunc.Node.Attr {\n\t\tswitch attr := v.(type) {\n\t\tcase string:\n\t\t\tif !strings.HasPrefix(key, `#`) {\n\t\t\t\tparFunc.Node.Attr[key] = macro(attr, workspace.Vars)\n\t\t\t}\n\t\tcase map[string]any:\n\t\t\tfor parkey, parval := range attr {\n\t\t\t\tswitch parmap := parval.(type) {\n\t\t\t\tcase map[string]any:\n\t\t\t\t\tfor textkey, textval := range parmap {\n\t\t\t\t\t\tvar result any\n\t\t\t\t\t\tswitch val := textval.(type) {\n\t\t\t\t\t\tcase string:\n\t\t\t\t\t\t\tresult = macro(val, workspace.Vars)\n\t\t\t\t\t\tcase []string:\n\t\t\t\t\t\t\tfor i, ival := range val {\n\t\t\t\t\t\t\t\tval[i] = macro(ival, workspace.Vars)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult = val\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif result != nil {\n\t\t\t\t\t\t\tparFunc.Node.Attr[key].(map[string]any)[parkey].(map[string]any)[textkey] = result\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfor key, v := range parFunc.Node.Attr {\n\t\tswitch attr := v.(type) {\n\t\tcase string:\n\t\t\tif strings.HasPrefix(key, `#`) {\n\t\t\t\tparFunc.Node.Attr[key[1:]] = attr\n\t\t\t\tdelete(parFunc.Node.Attr, key)\n\t\t\t}\n\t\t}\n\t}\n\tparFunc.Node.Text = macro(parFunc.Node.Text, workspace.Vars)\n\tfor inode, node := range parFunc.Node.Children {\n\t\tparFunc.Node.Children[inode].Text = macro(node.Text, workspace.Vars)\n\t}\n\tif len(out) > 0 {\n\t\tif len(owner.Children) > 0 && owner.Children[len(owner.Children)-1].Tag == tagText {\n\t\t\towner.Children[len(owner.Children)-1].Text += out\n\t\t} else {\n\t\t\tappendText(owner, out)\n\t\t}\n\t}\n}\n\nfunc getFunc(input string, curFunc tplFunc) (*[][]rune, int, *[]*[][]rune) {\n\tvar (\n\t\tcurp, skip, off, mode, lenParams int\n\t\tquote                            bool\n\t\tpair, ch                         rune\n\t\ttailpar                          *[]*[][]rune\n\t)\n\tvar params [][]rune\n\tsizeParam := 32 + len(input)/2\n\tparams = append(params, make([]rune, 0, sizeParam))\n\tif curFunc.Params == `*` {\n\t\tlenParams = 0xff\n\t} else {\n\t\tlenParams = len(strings.Split(curFunc.Params, `,`))\n\t}\n\tobjLevel := 0\n\tobjMode := 0\n\tlevel := 1\n\tif input[0] == '{' {\n\t\tmode = 1\n\t}\n\tskip = 1\nmain:\n\tfor off, ch = range input {\n\t\tif skip > 0 {\n\t\t\tskip--\n\t\t\tcontinue\n\t\t}\n\t\tif objLevel > 0 {\n\t\t\tparams[curp] = append(params[curp], ch)\n\t\t\tswitch ch {\n\t\t\tcase modes[objMode][0]:\n\t\t\t\tobjLevel++\n\t\t\tcase modes[objMode][1]:\n\t\t\t\tobjLevel--\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif pair > 0 {\n\t\t\tif ch != pair {\n\t\t\t\tparams[curp] = append(params[curp], ch)\n\t\t\t} else {\n\t\t\t\tif off+1 == len(input) || rune(input[off+1]) != pair {\n\t\t\t\t\tpair = 0\n\t\t\t\t\tif quote {\n\t\t\t\t\t\tparams[curp] = append(params[curp], ch)\n\t\t\t\t\t\tquote = false\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tparams[curp] = append(params[curp], ch)\n\t\t\t\t\tskip = 1\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif len(params[curp]) == 0 && mode == 0 && ch != modes[mode][1] && ch != ',' {\n\t\t\tif ch >= '!' {\n\t\t\t\tif ch == '\"' || ch == '`' {\n\t\t\t\t\tpair = ch\n\t\t\t\t} else if ch == '[' || ch == '{' {\n\t\t\t\t\tobjMode = 2\n\t\t\t\t\tif ch == '{' {\n\t\t\t\t\t\tobjMode = 1\n\t\t\t\t\t}\n\t\t\t\t\tobjLevel = 1\n\t\t\t\t\tparams[curp] = append(params[curp], ch)\n\t\t\t\t} else {\n\t\t\t\t\tif ch == modes[mode][0] {\n\t\t\t\t\t\tlevel++\n\t\t\t\t\t}\n\t\t\t\t\tparams[curp] = append(params[curp], ch)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch ch {\n\t\tcase '\"', '`':\n\t\t\tif mode == 0 {\n\t\t\t\tpair = ch\n\t\t\t\tquote = true\n\t\t\t}\n\t\tcase ',':\n\t\t\tif mode == 0 && level == 1 && len(params) < lenParams {\n\t\t\t\tparams = append(params, make([]rune, 0, sizeParam))\n\t\t\t\tcurp++\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase modes[mode][0]:\n\t\t\tlevel++\n\t\tcase modes[mode][1]:\n\t\t\tif level > 0 {\n\t\t\t\tlevel--\n\t\t\t}\n\t\t\tif level == 0 {\n\t\t\t\tif mode == 0 && (strings.Contains(curFunc.Params, `Body`) || strings.Contains(curFunc.Params, `Data`)) {\n\t\t\t\t\tvar isBody bool\n\t\t\t\t\tnext := off + 1\n\t\t\t\t\tfor next < len(input) {\n\t\t\t\t\t\tif rune(input[next]) == modes[1][0] {\n\t\t\t\t\t\t\tisBody = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif rune(input[next]) == ' ' || rune(input[next]) == '\\t' {\n\t\t\t\t\t\t\tnext++\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tif isBody {\n\t\t\t\t\t\tmode = 1\n\t\t\t\t\t\tfor _, keyp := range []string{`Body`, `Data`} {\n\t\t\t\t\t\t\tif strings.Contains(curFunc.Params, keyp) {\n\t\t\t\t\t\t\t\tirune := make([]rune, 0, sizeParam)\n\t\t\t\t\t\t\t\ts := keyp + `:`\n\t\t\t\t\t\t\t\tparams = append(params, append(irune, []rune(s)...))\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcurp++\n\t\t\t\t\t\tskip = next - off\n\t\t\t\t\t\tlevel = 1\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor tail, ok := tails[curFunc.Tag]; ok && off+2 < len(input) && input[off+1] == '.'; {\n\t\t\t\t\tvar found bool\n\t\t\t\t\tfor key, tailFunc := range tail.Tails {\n\t\t\t\t\t\tnext := off + 2\n\t\t\t\t\t\tif next < len(input) && strings.HasPrefix(input[next:], key) {\n\t\t\t\t\t\t\tvar isTail bool\n\t\t\t\t\t\t\tnext += len(key)\n\t\t\t\t\t\t\tfor next < len(input) {\n\t\t\t\t\t\t\t\tif rune(input[next]) == '(' || rune(input[next]) == '{' {\n\t\t\t\t\t\t\t\t\tisTail = true\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif rune(input[next]) == ' ' || rune(input[next]) == '\\t' {\n\t\t\t\t\t\t\t\t\tnext++\n\t\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif isTail {\n\t\t\t\t\t\t\t\tparTail, shift, _ := getFunc(input[next:], tailFunc.tplFunc)\n\t\t\t\t\t\t\t\toff = next\n\t\t\t\t\t\t\t\tfor ; shift > 0; shift-- {\n\t\t\t\t\t\t\t\t\t_, size := utf8.DecodeRuneInString(input[off:])\n\t\t\t\t\t\t\t\t\toff += size\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif tailpar == nil {\n\t\t\t\t\t\t\t\t\tfortail := make([]*[][]rune, 0)\n\t\t\t\t\t\t\t\t\ttailpar = &fortail\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t*parTail = append(*parTail, []rune(key))\n\t\t\t\t\t\t\t\t*tailpar = append(*tailpar, parTail)\n\t\t\t\t\t\t\t\tfound = true\n\t\t\t\t\t\t\t\tif tailFunc.Last {\n\t\t\t\t\t\t\t\t\tbreak main\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif !found {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak main\n\t\t\t}\n\t\t}\n\t\tparams[curp] = append(params[curp], ch)\n\t\tcontinue\n\t}\n\treturn &params, utf8.RuneCountInString(input[:off]), tailpar\n}\n\nfunc process(input string, owner *node, workspace *Workspace) {\n\tvar (\n\t\tnameOff, shift int\n\t\tcurFunc        tplFunc\n\t\tisFunc         bool\n\t\tparams         *[][]rune\n\t\ttailpars       *[]*[][]rune\n\t)\n\tinrune := []rune(input)\n\tname := make([]rune, 0, 128)\n\tfor off, ch := range inrune {\n\t\tif shift > 0 {\n\t\t\tshift--\n\t\t\tcontinue\n\t\t}\n\t\tif ch == '(' {\n\t\t\tif curFunc, isFunc = funcs[string(name[nameOff:])]; isFunc {\n\t\t\t\tif *workspace.Timeout {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tappendText(owner, macro(string(name[:nameOff]), workspace.Vars))\n\t\t\t\tname = name[:0]\n\t\t\t\tnameOff = 0\n\t\t\t\tparams, shift, tailpars = getFunc(string(inrune[off:]), curFunc)\n\t\t\t\tcallFunc(&curFunc, owner, workspace, params, tailpars)\n\t\t\t\tfor off+shift+3 < len([]rune(input)) &&\n\t\t\t\t\tstring(inrune[off+shift+1:off+shift+3]) == `.(` {\n\t\t\t\t\tvar next int\n\t\t\t\t\tparams, next, tailpars = getFunc(string(inrune[off+shift+2:]), curFunc)\n\t\t\t\t\tcallFunc(&curFunc, owner, workspace, params, tailpars)\n\t\t\t\t\tshift += next + 2\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif (ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') {\n\t\t\tnameOff = len(name) + 1\n\t\t}\n\t\tname = append(name, ch)\n\t}\n\tappendText(owner, string(name))\n}\n\nfunc parseArg(arg string, workspace *Workspace) (val string) {\n\tif strings.IndexByte(arg, '(') == -1 {\n\t\treturn arg\n\t}\n\n\tvar owner node\n\tprocess(arg, &owner, workspace)\n\tfor _, inode := range owner.Children {\n\t\tif inode.Tag == tagText {\n\t\t\tval += inode.Text\n\t\t}\n\t}\n\treturn\n}\n\n// Template2JSON converts templates to JSON data\nfunc Template2JSON(input string, timeout *bool, vars *map[string]string) []byte {\n\troot := node{}\n\tisclb := (*vars)[`clb`] == `true` || (*vars)[`clb`] == `1`\n\tkeyID := converter.StrToInt64((*vars)[\"key_id\"])\n\taccountID := (*vars)[\"account_id\"]\n\tsc := smart.SmartContract{\n\t\tCLB: isclb,\n\t\tVM:  script.GetVM(),\n\t\tTxSmart: &types.SmartTransaction{\n\t\t\tHeader: &types.Header{\n\t\t\t\tEcosystemID: converter.StrToInt64((*vars)[`ecosystem_id`]),\n\t\t\t\tKeyID:       keyID,\n\t\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t\t},\n\t\t},\n\t\tKey: &sqldb.Key{\n\t\t\tID:        keyID,\n\t\t\tAccountID: accountID,\n\t\t},\n\t\tDbTransaction: sqldb.NewDbTransaction(sqldb.DBConn),\n\t}\n\n\ttoVars := mapToVar(*vars)\n\tprocess(input, &root, &Workspace{Vars: toVars, Timeout: timeout, SmartContract: &sc})\n\tif root.Children == nil || *timeout {\n\t\treturn []byte(`[]`)\n\t}\n\tfor i, v := range root.Children {\n\t\tif v.Tag == `text` {\n\t\t\troot.Children[i].Text = macro(v.Text, toVars)\n\t\t}\n\t}\n\tout, err := json.Marshal(root.Children)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.JSONMarshallError, \"error\": err}).Error(\"marshalling template data to json\")\n\t\treturn []byte(err.Error())\n\t}\n\treturn out\n}\n\nfunc splitArray(in []rune) []string {\n\tvar quote, trim rune\n\tvar off int\n\tret := make([]string, 0, 32)\n\tbrace := make([]rune, 0, 32)\n\tif len(in) == 0 {\n\t\treturn ret\n\t}\n\tif in[0] == '[' && in[len(in)-1] == ']' {\n\t\tin = in[1 : len(in)-1]\n\t}\n\tnewPar := func(cur int) {\n\t\tpar := strings.TrimSpace(string(in[off:cur]))\n\t\tif rune(par[len(par)-1]) == trim {\n\t\t\tpar = par[:len(par)-1]\n\t\t}\n\t\tret = append(ret, par)\n\t}\n\tfor i, ch := range in {\n\t\tif ch == '[' {\n\t\t\tbrace = append(brace, ']')\n\t\t}\n\t\tif ch == '{' {\n\t\t\tbrace = append(brace, '}')\n\t\t}\n\t\tif len(brace) > 0 {\n\t\t\tif ch == brace[len(brace)-1] {\n\t\t\t\tbrace = brace[:len(brace)-1]\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif ch == quote {\n\t\t\tquote = 0\n\t\t\tcontinue\n\t\t}\n\t\tif quote != 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif ch == ' ' && off == i {\n\t\t\toff++\n\t\t\tcontinue\n\t\t}\n\t\tif ch == '\"' || ch == '`' || ch == '\\'' {\n\t\t\tquote = ch\n\t\t\tif off == i {\n\t\t\t\ttrim = ch\n\t\t\t\toff++\n\t\t\t}\n\t\t}\n\t\tif ch == ',' {\n\t\t\tnewPar(i)\n\t\t\toff = i + 1\n\t\t\ttrim = 0\n\t\t}\n\t}\n\tif off < len(in) {\n\t\tnewPar(len(in))\n\t}\n\treturn ret\n}\n\nfunc setVar(par *Workspace, key, value string) {\n\t(*par.Vars)[key] = Var{Value: value}\n}\n\nfunc getVar(par *Workspace, key string) string {\n\treturn (*par.Vars)[key].Value\n}\n\nfunc mapToVar(in map[string]string) *map[string]Var {\n\tret := make(map[string]Var)\n\tfor key, v := range in {\n\t\tret[key] = Var{Value: v}\n\t}\n\treturn &ret\n}\n"
  },
  {
    "path": "packages/transaction/ban.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage transaction\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n)\n\ntype banKey struct {\n\tTime time.Time   // banned till\n\tBad  []time.Time // time of bad tx\n}\n\nvar (\n\tbanList = make(map[int64]banKey)\n\tmutex   = &sync.RWMutex{}\n)\n\n// IsKeyBanned returns true if the key has been banned\nfunc IsKeyBanned(keyID int64) bool {\n\tmutex.RLock()\n\tif ban, ok := banList[keyID]; ok {\n\t\tmutex.RUnlock()\n\t\tnow := time.Now()\n\t\tif now.Before(ban.Time) {\n\t\t\treturn true\n\t\t}\n\t\tfor i := 0; i < conf.Config.BanKey.BadTx; i++ {\n\t\t\tif ban.Bad[i].Add(time.Duration(conf.Config.BanKey.BadTime) * time.Minute).After(now) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\t// Delete if time of all bad tx is old\n\t\tmutex.Lock()\n\t\tdelete(banList, keyID)\n\t\tmutex.Unlock()\n\t} else {\n\t\tmutex.RUnlock()\n\t}\n\treturn false\n}\n\n// BannedTill returns the time that the user has been banned till\nfunc BannedTill(keyID int64) string {\n\tmutex.RLock()\n\tdefer mutex.RUnlock()\n\tif ban, ok := banList[keyID]; ok {\n\t\treturn ban.Time.Format(`2006-01-02 15:04:05`)\n\t}\n\treturn ``\n}\n\n// BadTxForBan adds info about bad tx of the key\nfunc BadTxForBan(keyID int64) {\n\tvar (\n\t\tban banKey\n\t\tok  bool\n\t)\n\tmutex.Lock()\n\tdefer mutex.Unlock()\n\tnow := time.Now()\n\tif ban, ok = banList[keyID]; ok {\n\t\tvar bMin, count int\n\t\tfor i := 0; i < conf.Config.BanKey.BadTx; i++ {\n\t\t\tif ban.Bad[i].Add(time.Duration(conf.Config.BanKey.BadTime) * time.Minute).After(now) {\n\t\t\t\tcount++\n\t\t\t}\n\t\t\tif i > bMin && ban.Bad[i].Before(ban.Bad[bMin]) {\n\t\t\t\tbMin = i\n\t\t\t}\n\t\t}\n\t\tban.Bad[bMin] = now\n\t\tif count >= conf.Config.BanKey.BadTx-1 {\n\t\t\tban.Time = now.Add(time.Duration(conf.Config.BanKey.BanTime) * time.Minute)\n\t\t}\n\t} else {\n\t\tban = banKey{Bad: make([]time.Time, conf.Config.BanKey.BadTx)}\n\t\tban.Bad[0] = time.Now()\n\t}\n\tbanList[keyID] = ban\n}\n"
  },
  {
    "path": "packages/transaction/builder.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nfunc newTransaction(smartTx types.SmartTransaction, privateKey []byte, internal bool) (data, hash []byte, err error) {\n\tstp := &SmartTransactionParser{\n\t\tSmartContract: &smart.SmartContract{TxSmart: new(types.SmartTransaction)},\n\t}\n\tdata, err = stp.BinMarshalWithPrivate(&smartTx, privateKey, internal)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.MarshallingError, \"error\": err}).Error(\"marshalling smart contract to msgpack\")\n\t\treturn\n\t}\n\thash = stp.Hash\n\treturn\n\n}\n\nfunc NewInternalTransaction(smartTx types.SmartTransaction, privateKey []byte) (data, hash []byte, err error) {\n\treturn newTransaction(smartTx, privateKey, true)\n}\n\nfunc NewTransactionInProc(smartTx types.SmartTransaction, privateKey []byte) (data, hash []byte, err error) {\n\treturn newTransaction(smartTx, privateKey, false)\n}\n\n// CreateTransaction creates transaction\nfunc CreateTransaction(data, hash []byte, keyID, tnow int64) error {\n\ttx := &sqldb.Transaction{\n\t\tHash:     hash,\n\t\tData:     data[:],\n\t\tType:     types.SmartContractTxType,\n\t\tKeyID:    keyID,\n\t\tHighRate: sqldb.TransactionRateOnBlock,\n\t\tTime:     tnow,\n\t}\n\tif err := tx.Create(nil); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating new transaction\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// CreateDelayTransactionHighRate creates transaction\nfunc CreateDelayTransactionHighRate(data, hash []byte, keyID, highRate int64) *sqldb.Transaction {\n\n\tt := int8(highRate)\n\ttx := &sqldb.Transaction{\n\t\tHash:     hash,\n\t\tData:     data[:],\n\t\tType:     getTxTxType(t),\n\t\tKeyID:    keyID,\n\t\tHighRate: sqldb.GetTxRateByTxType(t),\n\t}\n\treturn tx\n}\n\nfunc getTxTxType(rate int8) int8 {\n\tret := int8(1)\n\tswitch rate {\n\tcase types.SmartContractTxType, types.StopNetworkTxType:\n\t\tret = rate\n\tdefault:\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "packages/transaction/cache.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\ntype transactionCache struct {\n\tmutex sync.RWMutex\n\tcache map[string]*Transaction\n}\n\nvar txCache = &transactionCache{cache: make(map[string]*Transaction)}\n\n// CleanCache cleans cache of transaction parsers\nfunc CleanCache() {\n\ttxCache.Clean()\n}\n\nfunc (tc *transactionCache) Get(hash string) (t *Transaction, ok bool) {\n\ttc.mutex.RLock()\n\tdefer tc.mutex.RUnlock()\n\n\tt, ok = tc.cache[hash]\n\treturn\n}\n\nfunc (tc *transactionCache) Set(t *Transaction) {\n\ttc.mutex.Lock()\n\tdefer tc.mutex.Unlock()\n\ttc.cache[fmt.Sprintf(\"%x\", t.Hash())] = t\n}\n\nfunc (tc *transactionCache) Clean() {\n\ttc.mutex.Lock()\n\tdefer tc.mutex.Unlock()\n\n\ttc.cache = make(map[string]*Transaction)\n}\n"
  },
  {
    "path": "packages/transaction/contract.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\nconst (\n\terrUnknownContract = `Cannot find %s contract`\n)\n\nfunc CreateContract(contractName string, keyID int64, params map[string]any,\n\tprivateKey []byte) error {\n\tecosysID, _ := converter.ParseName(contractName)\n\tif ecosysID == 0 {\n\t\tecosysID = 1\n\t}\n\tcontract := smart.GetContract(contractName, uint32(ecosysID))\n\tif contract == nil {\n\t\treturn fmt.Errorf(errUnknownContract, contractName)\n\t}\n\tsc := types.SmartTransaction{\n\t\tHeader: &types.Header{\n\t\t\tID:          int(contract.Info().ID),\n\t\t\tEcosystemID: ecosysID,\n\t\t\tKeyID:       keyID,\n\t\t\tTime:        time.Now().Unix(),\n\t\t\tNetworkID:   conf.Config.LocalConf.NetworkID,\n\t\t},\n\t\tParams: params,\n\t}\n\ttxData, _, err := NewTransactionInProc(sc, privateKey)\n\tif err == nil {\n\t\trtx := &Transaction{}\n\t\tif err = rtx.Unmarshall(bytes.NewBuffer(txData), true); err == nil {\n\t\t\t//err = sqldb.SendTx(rtx, sc.KeyId)\n\t\t\terr = sqldb.SendTxBatches([]*sqldb.RawTx{rtx.SetRawTx()})\n\t\t}\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "packages/transaction/db.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"fmt\"\n\n\t\"gorm.io/gorm\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar (\n\tErrDuplicatedTx = errors.New(\"Duplicated transaction\")\n\tErrNotComeTime  = errors.New(\"Transaction processing time has not come\")\n\tErrExpiredTime  = errors.New(\"Transaction processing time is expired\")\n\tErrEarlyTime    = utils.WithBan(errors.New(\"Early transaction time\"))\n\tErrEmptyKey     = utils.WithBan(errors.New(\"KeyID is empty\"))\n)\n\n// InsertInLogTx is inserting tx in log\n//func InsertInLogTx(t *Transaction, blockID int64) error {\n//\tltx := &sqldb.LogTransaction{Hash: t.TxHash, Block: blockID}\n//\tif err := ltx.Create(t.DbTransaction); err != nil {\n//\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"insert logged transaction\")\n//\t\treturn utils.ErrInfo(err)\n//\t}\n//\treturn nil\n//}\n\n// CheckLogTx checks if this transaction exists\n// And it would have successfully passed a frontal test\nfunc CheckLogTx(txHash []byte, logger *log.Entry) error {\n\tlogTx := &sqldb.LogTransaction{}\n\tfound, err := logTx.GetByHash(nil, txHash)\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting log transaction by hash\")\n\t\treturn err\n\t}\n\tif found {\n\t\tlogger.WithFields(log.Fields{\"tx_hash\": txHash, \"type\": consts.DuplicateObject}).Warning(\"double tx in log transactions\")\n\t\treturn ErrDuplicatedTx\n\t}\n\treturn nil\n}\n\n// DeleteQueueTx deletes a transaction from the queue\nfunc DeleteQueueTx(dbTx *sqldb.DbTransaction, hash []byte) error {\n\tdelQueueTx := &sqldb.QueueTx{Hash: hash}\n\terr := delQueueTx.DeleteTx(dbTx)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"deleting transaction from queue\")\n\t\treturn err\n\t}\n\t// Because we process transactions with verified=0 in queue_parser_tx, after processing we need to delete them\n\terr = sqldb.DeleteTransactionByHash(dbTx, hash)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"deleting transaction if unused\")\n\t\treturn err\n\t}\n\t//err = sqldb.DeleteTransactionsAttemptsByHash(dbTx, hash)\n\t//if err != nil {\n\t//\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"deleting DeleteTransactionsAttemptsByHash\")\n\t//\treturn err\n\t//}\n\treturn nil\n}\n\nfunc MarkTransactionBad(hash []byte, errText string) error {\n\tif hash == nil {\n\t\treturn nil\n\t}\n\tif len(errText) > 255 {\n\t\terrText = errText[:255] + \"...\"\n\t}\n\tlog.WithFields(log.Fields{\"type\": consts.BadTxError, \"tx_hash\": hash, \"error\": errText}).Debug(\"tx marked as bad\")\n\n\treturn sqldb.NewDbTransaction(sqldb.DBConn).Connection().Transaction(func(tx *gorm.DB) error {\n\t\t// looks like there is no hash in queue_tx at this moment\n\t\tqtx := &sqldb.QueueTx{}\n\t\t_, err := qtx.GetByHash(sqldb.NewDbTransaction(tx), hash)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"getting tx by hash from queue\")\n\t\t\treturn err\n\t\t}\n\n\t\tif qtx.FromGate == 0 {\n\t\t\tm := &sqldb.TransactionStatus{}\n\t\t\terr = m.SetError(sqldb.NewDbTransaction(tx), errText, hash)\n\t\t\tif err != nil {\n\t\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"setting transaction status error\")\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\terr = DeleteQueueTx(sqldb.NewDbTransaction(tx), hash)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Debug(\"deleting transaction from queue\")\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t})\n}\n\n// ProcessQueueTransaction writes transactions into the queue\n//func ProcessQueueTransaction(dbTx *sqldb.DbTransaction, hash, binaryTx []byte, myTx bool) error {\n//\tt, err := UnmarshallTransaction(bytes.NewBuffer(binaryTx), true)\n//\tif err != nil {\n//\t\treturn err\n//\t}\n//\n//\tif err = t.Check(time.Now().Unix(), true); err != nil {\n//\t\tif err != ErrEarlyTime {\n//\t\t\treturn err\n//\t\t}\n//\t\treturn nil\n//\t}\n//\n//\tif t.TxKeyID == 0 {\n//\t\terrStr := \"undefined keyID\"\n//\t\treturn errors.New(errStr)\n//\t}\n//\tvar found bool\n//\ttx := &sqldb.Transaction{}\n//\tfound, err = tx.Get(hash)\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting transaction by hash\")\n//\t\treturn utils.ErrInfo(err)\n//\t}\n//\tif found {\n//\t\terr = sqldb.DeleteTransactionByHash(dbTx, hash)\n//\t\tif err != nil {\n//\t\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting transaction by hash\")\n//\t\t\treturn utils.ErrInfo(err)\n//\t\t}\n//\t}\n//\t// put with verified=1\n//\tvar expedite decimal.Decimal\n//\tif len(t.TxSmart.GetExpedite) > 0 {\n//\t\texpedite, err = decimal.NewFromString(t.TxSmart.GetExpedite)\n//\t\tif err != nil {\n//\t\t\treturn utils.ErrInfo(err)\n//\t\t}\n//\t}\n//\tnewTx := &sqldb.Transaction{\n//\t\tHash:     hash,\n//\t\tData:     binaryTx,\n//\t\tType:     int8(t.TxType),\n//\t\tKeyID:    t.TxKeyID,\n//\t\tGetExpedite: expedite,\n//\t\tTime:     t.TxTime,\n//\t\tVerified: 1,\n//\t}\n//\terr = newTx.Create()\n//\tif err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"creating new transaction\")\n//\t\treturn utils.ErrInfo(err)\n//\t}\n//\n//\tdelQueueTx := &sqldb.QueueTx{Hash: hash}\n//\tif err = delQueueTx.DeleteTx(dbTx); err != nil {\n//\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"deleting transaction from queue\")\n//\t\treturn utils.ErrInfo(err)\n//\t}\n//\n//\treturn nil\n//}\n\n// ProcessTransactionsQueue parses new transactions\nfunc ProcessTransactionsQueue(dbTx *sqldb.DbTransaction) error {\n\tall, err := sqldb.GetAllUnverifiedAndUnusedTransactions(dbTx, syspar.GetMaxTxCount())\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all unverified and unused transactions\")\n\t\treturn err\n\t}\n\t//for i := 0; i < len(all); i++ {\n\t//\terr := ProcessQueueTransaction(dbTx, all[i].Hash, all[i].Data, false)\n\t//\tif err != nil {\n\t//\t\tMarkTransactionBad(dbTx, all[i].Hash, err.Error())\n\t//\t\treturn utils.ErrInfo(err)\n\t//\t}\n\t//\tlog.Debug(\"transaction parsed successfully\")\n\t//}\n\treturn ProcessQueueTransactionBatches(dbTx, all)\n}\n\n// AllTxParser parses new transactions\nfunc ProcessTransactionsAttempt(dbTx *sqldb.DbTransaction) error {\n\tall, err := sqldb.FindTxAttemptCount(dbTx, consts.MaxTXAttempt)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"getting all  transactions attempt > consts.MaxTXAttempt\")\n\t\treturn err\n\t}\n\tfor _, data := range all {\n\t\terr := MarkTransactionBad(data.Hash, fmt.Sprintf(\"The limit of %d attempts has been reached\", consts.MaxTXAttempt))\n\t\tif err != nil {\n\t\t\treturn utils.ErrInfo(err)\n\t\t}\n\t\tlog.Debug(\"transaction attempt deal successfully\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/transaction/deliver.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage transaction\n\nimport (\n\t\"math/rand\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\ntype DeliverProvider interface {\n\tSysUpdateWorker(*sqldb.DbTransaction) error\n\tSysTableColByteaWorker(*sqldb.DbTransaction) error\n\tFlushVM()\n}\n\ntype InToCxt struct {\n\tSqlDbSavePoint string\n\tGenBlock       bool\n\tDbTransaction  *sqldb.DbTransaction\n\tBlockHeader    *types.BlockHeader\n\tPreBlockHeader *types.BlockHeader\n\tNotifications  types.Notifications\n\tRand           *rand.Rand\n\tTxCheckLimits  *Limits\n\tOutputsMap     map[sqldb.KeyUTXO][]sqldb.SpentInfo\n\tPrevSysPar     map[string]string\n\tEcoParams      []sqldb.EcoParam\n}\n\ntype OutCtx struct {\n\tSysUpdate    bool\n\tRollBackTx   []*types.RollbackTx\n\tTxResult     *pbgo.TxResult\n\tTxOutputsMap map[sqldb.KeyUTXO][]sqldb.SpentInfo\n\tTxInputsMap  map[sqldb.KeyUTXO][]sqldb.SpentInfo\n}\n\ntype OutCtxOption func(b *OutCtx)\n\nfunc (tr *OutCtx) Apply(opts ...OutCtxOption) {\n\tfor _, opt := range opts {\n\t\tif opt == nil {\n\t\t\tcontinue\n\t\t}\n\t\topt(tr)\n\t}\n\treturn\n}\n\nfunc WithOutCtxTxResult(ret *pbgo.TxResult) OutCtxOption {\n\treturn func(b *OutCtx) {\n\t\tb.TxResult = ret\n\t}\n}\n\nfunc WithOutCtxSysUpdate(ret bool) OutCtxOption {\n\treturn func(b *OutCtx) {\n\t\tb.SysUpdate = ret\n\t}\n}\n\nfunc WithOutCtxRollBackTx(ret []*types.RollbackTx) OutCtxOption {\n\treturn func(b *OutCtx) {\n\t\tb.RollBackTx = ret\n\t}\n}\n\nfunc WithOutCtxTxOutputs(txOutputsMap map[sqldb.KeyUTXO][]sqldb.SpentInfo) OutCtxOption {\n\treturn func(b *OutCtx) {\n\t\tb.TxOutputsMap = txOutputsMap\n\t}\n}\n\nfunc WithOutCtxTxInputs(txInputsMap map[sqldb.KeyUTXO][]sqldb.SpentInfo) OutCtxOption {\n\treturn func(b *OutCtx) {\n\t\tb.TxInputsMap = txInputsMap\n\t}\n}\n"
  },
  {
    "path": "packages/transaction/first_block.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/migration\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/vmihailenco/msgpack/v5\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tfirstEcosystemID = 1\n\tfirstAppID       = 1\n)\n\n// FirstBlockParser is parser wrapper\ntype FirstBlockParser struct {\n\tLogger        *log.Entry\n\tDbTransaction *sqldb.DbTransaction\n\tData          *types.FirstBlock\n\tTimestamp     int64\n\tTxHash        []byte\n\tPayload       []byte // transaction binary data\n}\n\nfunc (f *FirstBlockParser) txType() byte                { return f.Data.TxType() }\nfunc (f *FirstBlockParser) txHash() []byte              { return f.TxHash }\nfunc (f *FirstBlockParser) txPayload() []byte           { return f.Payload }\nfunc (f *FirstBlockParser) txTime() int64               { return f.Timestamp }\nfunc (f *FirstBlockParser) txKeyID() int64              { return f.Data.KeyID }\nfunc (f *FirstBlockParser) txExpedite() decimal.Decimal { return decimal.Decimal{} }\nfunc (s *FirstBlockParser) setTimestamp()               { s.Timestamp = time.Now().UnixMilli() }\n\nfunc (f *FirstBlockParser) TxRollback() error                                      { return nil }\nfunc (f *FirstBlockParser) SysUpdateWorker(dbTx *sqldb.DbTransaction) error        { return nil }\nfunc (f *FirstBlockParser) SysTableColByteaWorker(dbTx *sqldb.DbTransaction) error { return nil }\nfunc (f *FirstBlockParser) FlushVM()                                               {}\n\nfunc (f *FirstBlockParser) Init(in *InToCxt) error {\n\tf.Logger = log.WithFields(log.Fields{})\n\tf.DbTransaction = in.DbTransaction\n\treturn nil\n}\n\nfunc (f *FirstBlockParser) Validate() error {\n\treturn nil\n}\n\nfunc (f *FirstBlockParser) Action(in *InToCxt, out *OutCtx) (err error) {\n\tif in.BlockHeader.BlockId > 1 {\n\t\treturn nil\n\t}\n\tlogger := f.Logger\n\tdata := f.Data\n\tdbTx := in.DbTransaction\n\tid := int64(0)\n\tkeyID := crypto.Address(data.PublicKey)\n\tnodeKeyID := crypto.Address(data.NodePublicKey)\n\terr = sqldb.ExecSchemaEcosystem(dbTx, migration.SqlData{\n\t\tEcosystem:   firstEcosystemID,\n\t\tWallet:      keyID,\n\t\tName:        consts.DefaultEcosystemName,\n\t\tFounder:     keyID,\n\t\tAppID:       firstAppID,\n\t\tAccount:     converter.AddressToString(keyID),\n\t\tDigits:      consts.MoneyDigits,\n\t\tTokenSymbol: consts.DefaultTokenSymbol,\n\t\tTokenName:   consts.DefaultTokenName,\n\t})\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"executing ecosystem schema\")\n\t\treturn err\n\t}\n\n\tamount := decimal.New(consts.FounderAmount, int32(consts.MoneyDigits)).String()\n\n\ttaxes := &sqldb.PlatformParameter{Name: `taxes_wallet`}\n\tif err = taxes.SaveArray(dbTx, [][]string{{\"1\", converter.Int64ToStr(keyID)}}); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"saving taxes_wallet array\")\n\t\treturn err\n\t}\n\n\terr = sqldb.GetDB(dbTx).Exec(`update \"1_platform_parameters\" SET value = ? where name = 'test'`, strconv.FormatInt(data.Test, 10)).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating test parameter\")\n\t\treturn err\n\t}\n\n\terr = sqldb.GetDB(dbTx).Exec(`Update \"1_platform_parameters\" SET value = ? where name = 'private_blockchain'`, strconv.FormatUint(data.PrivateBlockchain, 10)).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating private_blockchain\")\n\t\treturn err\n\t}\n\n\tif err = syspar.SysUpdate(dbTx); err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating syspar\")\n\t\treturn err\n\t}\n\n\terr = sqldb.GetDB(dbTx).Exec(`insert into \"1_keys\" (id,account,pub,amount) values(?,?,?,?),(?,?,?,?)`,\n\t\tkeyID, converter.AddressToString(keyID), data.PublicKey, 0, nodeKeyID, converter.AddressToString(nodeKeyID), data.NodePublicKey, 0).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"inserting key\")\n\t\treturn err\n\t}\n\n\terr = sqldb.GetDB(dbTx).Exec(`insert into \"spent_info\" (output_index,output_tx_hash,output_key_id,output_value,ecosystem,block_id,type) values(?,?,?,?,?,?,?)`,\n\t\t0, f.TxHash, keyID, amount, 1, 1, consts.UTXO_Type_First_Block).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"inserting spent info\")\n\t\treturn err\n\t}\n\n\tid, err = dbTx.GetNextID(\"1_pages\")\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = sqldb.GetDB(dbTx).Exec(`insert into \"1_pages\" (id,name,menu,value,conditions) values(?, 'default_page',\n\t\t  'default_menu', ?, 'ContractConditions(\"@1DeveloperCondition\")')`,\n\t\tid, syspar.SysString(`default_ecosystem_page`)).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"inserting default page\")\n\t\treturn err\n\t}\n\tid, err = dbTx.GetNextID(\"1_menu\")\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = sqldb.GetDB(dbTx).Exec(`insert into \"1_menu\" (id,name,value,title,conditions) values(?, 'default_menu', ?, ?, 'ContractAccess(\"@1EditMenu\")')`,\n\t\tid, syspar.SysString(`default_ecosystem_menu`), `default`).Error\n\tif err != nil {\n\t\tlogger.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"inserting default menu\")\n\t\treturn err\n\t}\n\terr = smart.LoadContract(dbTx, 1)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := syspar.SysTableColType(dbTx); err != nil {\n\t\treturn err\n\t}\n\tsyspar.SetFirstBlockData(data)\n\tsyspar.SetFirstBlockTimestamp(time.UnixMilli(f.Timestamp).Unix())\n\treturn nil\n}\n\nfunc (s *FirstBlockParser) BinMarshal(data *types.FirstBlock) ([]byte, error) {\n\ts.Data = data\n\tvar buf []byte\n\tvar err error\n\tbuf, err = msgpack.Marshal(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts.setTimestamp()\n\ts.Payload = buf\n\ts.TxHash = crypto.DoubleHash(s.Payload)\n\tbuf, err = msgpack.Marshal(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf = append([]byte{s.txType()}, buf...)\n\treturn buf, nil\n}\n\nfunc (f *FirstBlockParser) Unmarshal(buffer *bytes.Buffer) error {\n\tbuffer.UnreadByte()\n\tif err := msgpack.Unmarshal(buffer.Bytes()[1:], f); err != nil {\n\t\treturn errors.Wrap(err, \"first block Unmarshal err\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/transaction/limits.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage transaction\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype LimitMode int\n\nconst (\n\tletPreprocess LimitMode = 0x0001 // checking before generating block\n\tletGenBlock   LimitMode = 0x0002 // checking during generating block\n\tletParsing    LimitMode = 0x0004 // common checking during parsing block\n)\n\nfunc GetLetPreprocess() LimitMode {\n\treturn letPreprocess\n}\n\nfunc GetLetGenBlock() LimitMode {\n\treturn letGenBlock\n}\n\nfunc GetLetParsing() LimitMode {\n\treturn letParsing\n}\n\n// Limits is used for saving current limit information\ntype Limits struct {\n\tMode     LimitMode\n\tLimiters []Limiter // the list of limiters\n}\n\n// Limiter describes interface functions for limits\ntype Limiter interface {\n\tinit()\n\tcheck(TransactionCaller, LimitMode) error\n}\n\ntype limiterModes struct {\n\tlimiter Limiter\n\tmodes   LimitMode // combination of letPreprocess letGenBlock letParsing\n}\n\nvar (\n\t// ErrLimitSkip returns when tx should be skipped during generating block\n\tErrLimitSkip = errors.New(`skip tx`)\n\t// ErrLimitStop returns when the generation of the block should be stopped\n\tErrLimitStop = errors.New(`stop generating block`)\n)\n\n// NewLimits initializes Limits structure.\nfunc NewLimits(b LimitMode) (limits *Limits) {\n\tlimits = &Limits{Limiters: make([]Limiter, 0, 8)}\n\n\tlimits.Mode = b\n\n\tallLimiters := []limiterModes{\n\t\t{limiter: &txMaxSize{}, modes: letPreprocess | letParsing},\n\t\t{limiter: &txUserLimit{}, modes: letPreprocess | letParsing},\n\t\t{limiter: &txMaxLimit{}, modes: letPreprocess | letParsing},\n\t\t{limiter: &txUserEcosysLimit{}, modes: letPreprocess | letParsing},\n\t\t{limiter: &timeBlockLimit{}, modes: letGenBlock},\n\t\t{limiter: &txMaxFuel{}, modes: letGenBlock | letParsing},\n\t}\n\tfor _, limiter := range allLimiters {\n\t\tif limiter.modes&limits.Mode == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tlimiter.limiter.init()\n\t\tlimits.Limiters = append(limits.Limiters, limiter.limiter)\n\t}\n\treturn\n}\n\n// CheckLimit calls each limiter\nfunc (limits *Limits) CheckLimit(t TransactionCaller) error {\n\tfor _, limiter := range limits.Limiters {\n\t\tif err := limiter.check(t, limits.Mode); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc limitError(limitName, msg string, args ...any) error {\n\terr := fmt.Errorf(msg, args...)\n\tlog.WithFields(log.Fields{\"type\": consts.BlockError, \"error\": err}).Error(limitName)\n\treturn script.SetVMError(`panic`, err)\n}\n\n// Checking the max tx in the block\ntype txMaxLimit struct {\n\tCount int // the current count\n\tLimit int // max count of tx in the block\n}\n\nfunc (bl *txMaxLimit) init() {\n\tbl.Limit = syspar.GetMaxTxCount()\n}\n\nfunc (bl *txMaxLimit) check(t TransactionCaller, mode LimitMode) error {\n\tbl.Count++\n\tif bl.Count+1 > bl.Limit && mode == letPreprocess {\n\t\treturn errors.WithMessage(ErrLimitStop, \"txMaxLimit\")\n\t}\n\tif bl.Count > bl.Limit {\n\t\treturn limitError(`txMaxLimit`, `Max tx in the block`)\n\t}\n\treturn nil\n}\n\n// Checking the time of the start of generating block\ntype timeBlockLimit struct {\n\tStart time.Time     // the time of the start of generating block\n\tLimit time.Duration // the maximum time\n}\n\nfunc (bl *timeBlockLimit) init() {\n\tbl.Start = time.Now()\n\tbl.Limit = time.Millisecond * time.Duration(syspar.GetMaxBlockGenerationTime())\n}\n\nfunc (bl *timeBlockLimit) check(t TransactionCaller, mode LimitMode) error {\n\tif time.Since(bl.Start) < bl.Limit {\n\t\treturn nil\n\t}\n\n\tif mode == letGenBlock {\n\t\treturn errors.WithMessage(ErrLimitStop, \"timeBlockLimit\")\n\t}\n\n\treturn limitError(\"txBlockTimeLimit\", \"Block generation time exceeded\")\n}\n\n// Checking the max tx from one user in the block\ntype txUserLimit struct {\n\tTxUsers map[int64]int // the counter of tx from one user\n\tLimit   int           // the value of max tx from one user\n}\n\nfunc (bl *txUserLimit) init() {\n\tbl.TxUsers = make(map[int64]int)\n\tbl.Limit = syspar.GetMaxBlockUserTx()\n}\n\nfunc (bl *txUserLimit) check(t TransactionCaller, mode LimitMode) error {\n\tvar (\n\t\tcount int\n\t\tok    bool\n\t)\n\tkeyID := t.txKeyID()\n\tif count, ok = bl.TxUsers[keyID]; ok {\n\t\tif count+1 > bl.Limit && mode == letPreprocess {\n\t\t\treturn ErrLimitSkip\n\t\t}\n\t\tif count > bl.Limit {\n\t\t\treturn limitError(`txUserLimit`, `Max tx from one user %d`, keyID)\n\t\t}\n\t}\n\tbl.TxUsers[keyID] = count + 1\n\treturn nil\n}\n\n// Checking the max tx from one user in the ecosystem contracts\ntype ecosysLimit struct {\n\tTxUsers map[int64]int // the counter of tx from one user in the ecosystem\n\tLimit   int           // the value of max tx from one user in the ecosystem\n}\n\ntype txUserEcosysLimit struct {\n\tTxEcosys map[int64]ecosysLimit // the counter of tx from one user in ecosystems\n}\n\nfunc (bl *txUserEcosysLimit) init() {\n\tbl.TxEcosys = make(map[int64]ecosysLimit)\n}\n\nfunc (bl *txUserEcosysLimit) check(t TransactionCaller, mode LimitMode) error {\n\tkeyID := t.txKeyID()\n\tsmart, ok := t.(*SmartTransactionParser)\n\tif !ok {\n\t\treturn nil\n\t}\n\tecosystemID := smart.TxSmart.EcosystemID\n\tif val, ok := bl.TxEcosys[ecosystemID]; ok {\n\t\tif user, ok := val.TxUsers[keyID]; ok {\n\t\t\tif user+1 > val.Limit && mode == letPreprocess {\n\t\t\t\treturn ErrLimitSkip\n\t\t\t}\n\t\t\tif user > val.Limit {\n\t\t\t\treturn limitError(`txUserEcosysLimit`, `Max tx from one user %d in ecosystem %d`,\n\t\t\t\t\tkeyID, ecosystemID)\n\t\t\t}\n\t\t\tval.TxUsers[keyID] = user + 1\n\t\t} else {\n\t\t\tval.TxUsers[keyID] = 1\n\t\t}\n\t} else {\n\t\tlimit := syspar.GetMaxBlockUserTx()\n\t\tbl.TxEcosys[ecosystemID] = ecosysLimit{TxUsers: make(map[int64]int), Limit: limit}\n\t\tbl.TxEcosys[ecosystemID].TxUsers[keyID] = 1\n\t}\n\treturn nil\n}\n\n// Checking the max tx & block size\ntype txMaxSize struct {\n\tSize       int64 // the current size of the block\n\tLimitBlock int64 // max size of the block\n\tLimitTx    int64 // max size of tx\n}\n\nfunc (bl *txMaxSize) init() {\n\tbl.LimitBlock = syspar.GetMaxBlockSize()\n\tbl.LimitTx = syspar.GetMaxTxSize()\n}\n\nfunc (bl *txMaxSize) check(t TransactionCaller, mode LimitMode) error {\n\tsize := int64(len(append([]byte{t.txType()}, t.txPayload()...)))\n\tif size > bl.LimitTx {\n\t\treturn limitError(`txMaxSize`, `Max size of tx`)\n\t}\n\tbl.Size += size\n\tif bl.Size > bl.LimitBlock {\n\t\tif mode == letPreprocess {\n\t\t\treturn errors.WithMessage(ErrLimitStop, \"txMaxSize\")\n\t\t}\n\t\treturn limitError(`txMaxSize`, `Max size of the block`)\n\t}\n\treturn nil\n}\n\n// Checking the max tx & block size\ntype txMaxFuel struct {\n\tFuel       int64 // the current fuel of the block\n\tLimitBlock int64 // max fuel of the block\n\tLimitTx    int64 // max fuel of tx\n}\n\nfunc (bl *txMaxFuel) init() {\n\tbl.LimitBlock = syspar.GetMaxBlockFuel()\n\tbl.LimitTx = syspar.GetMaxTxFuel()\n}\n\nfunc (bl *txMaxFuel) check(t TransactionCaller, mode LimitMode) error {\n\tsmart, ok := t.(*SmartTransactionParser)\n\tif !ok {\n\t\treturn nil\n\t}\n\tfuel := smart.TxFuel\n\tif fuel > bl.LimitTx {\n\t\treturn limitError(`txMaxFuel`, `Max fuel of tx %d > %d`, fuel, bl.LimitTx)\n\t}\n\tbl.Fuel += fuel\n\tif bl.Fuel > bl.LimitBlock {\n\t\tif mode == letGenBlock {\n\t\t\treturn errors.WithMessage(ErrLimitStop, \"txMaxFuel\")\n\t\t}\n\t\treturn limitError(`txMaxFuel`, `Max fuel of the block`)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/transaction/play.go",
    "content": "package transaction\n\nimport (\n\t\"encoding/hex\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// GetLogger returns logger\nfunc (t *Transaction) GetLogger() *log.Entry {\n\tvar logger *log.Entry\n\tif t.Inner != nil {\n\t\tlogger = log.WithFields(log.Fields{\"tx_type\": t.Type(), \"tx_time\": t.Timestamp(), \"tx_wallet_id\": t.KeyID()})\n\t}\n\tif t.BlockHeader != nil {\n\t\tlogger = logger.WithFields(log.Fields{\"block_id\": t.BlockHeader.BlockId, \"block_time\": t.BlockHeader.Timestamp, \"block_wallet_id\": t.BlockHeader.KeyId, \"block_state_id\": t.BlockHeader.EcosystemId, \"block_hash\": t.BlockHeader.BlockHash, \"block_version\": t.BlockHeader.Version})\n\t}\n\tif t.PreBlockHeader != nil {\n\t\tlogger = logger.WithFields(log.Fields{\"pre_block_id\": t.PreBlockHeader.BlockId, \"pre_block_time\": t.PreBlockHeader.Timestamp, \"pre_block_wallet_id\": t.PreBlockHeader.KeyId, \"pre_block_state_id\": t.PreBlockHeader.EcosystemId, \"pre_block_hash\": t.PreBlockHeader.BlockHash, \"pre_block_version\": t.PreBlockHeader.Version})\n\t}\n\treturn logger\n}\n\nfunc (t *Transaction) Play() error {\n\tif err := t.Inner.Init(t.InToCxt); err != nil {\n\t\treturn err\n\t}\n\treturn t.Inner.Action(t.InToCxt, t.OutCtx)\n}\n\nfunc (t *Transaction) Check(checkTime int64) error {\n\tif t.KeyID() == 0 {\n\t\treturn ErrEmptyKey\n\t}\n\tlogger := log.WithFields(log.Fields{\"tx_hash\": hex.EncodeToString(t.Hash()), \"tx_time\": t.Timestamp(), \"check_time\": checkTime, \"type\": consts.ParameterExceeded})\n\tif time.UnixMilli(t.Timestamp()).Unix() > checkTime {\n\t\t//if time.UnixMilli(t.Timestamp()).Unix()-consts.MaxTxForw > checkTime {\n\t\t//\tlogger.WithFields(log.Fields{\"tx_max_forw\": consts.MaxTxForw}).Errorf(\"time in the tx cannot be more than %d seconds of block time \", consts.MaxTxForw)\n\t\t//\treturn ErrNotComeTime\n\t\t//}\n\t\tlogger.Error(\"time in the tx cannot be more than of block time \")\n\t\treturn ErrEarlyTime\n\t}\n\n\tif t.Type() != types.StopNetworkTxType {\n\t\tif time.UnixMilli(t.Timestamp()).Unix() < checkTime-consts.MaxTxBack {\n\t\t\tlogger.WithFields(log.Fields{\"tx_max_back\": consts.MaxTxBack, \"tx_type\": t.Type()}).Errorf(\"time in the tx cannot be less then %d seconds of block time\", consts.MaxTxBack)\n\t\t\treturn ErrExpiredTime\n\t\t}\n\t}\n\terr := CheckLogTx(t.Hash(), logger)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// CallContract calls the contract functions according to the specified flags\n//func (t *Transaction) CallContract(point int) error {\n//\n//\tvar err error\n//\tt.TxSize = int64(len(t.Raw.payload))\n//\tt.VM = smart.GetVM()\n//\tt.CLB = false\n//\tt.Rollback = true\n//\tt.SysUpdate = false\n//\tt.RollBackTx = make([]*sqldb.RollbackTx, 0)\n//\tif t.GenBlock {\n//\t\tt.TimeLimit = syspar.GetMaxBlockGenerationTime()\n//\t}\n//\n//\tt.TxResult, err = t.SmartContract.CallContract(point)\n//\tif err == nil && t.TxSmart != nil {\n//\t\tif t.Penalty {\n//\t\t\tif t.FlushRollback != nil {\n//\t\t\t\tflush := t.FlushRollback\n//\t\t\t\tfor i := len(flush) - 1; i >= 0; i-- {\n//\t\t\t\t\tflush[i].FlushVM()\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\terr = t.TxCheckLimits.CheckLimit(t)\n//\t}\n//\tif err != nil {\n//\t\tif t.FlushRollback != nil {\n//\t\t\tflush := t.FlushRollback\n//\t\t\tfor i := len(flush) - 1; i >= 0; i-- {\n//\t\t\t\tflush[i].FlushVM()\n//\t\t\t}\n//\t\t}\n//\t}\n//\treturn err\n//}\n/*\nfunc (t *Transaction) CallCLBContract() (resultContract string, flushRollback []smart.FlushInfo, err error) {\n\n\tt.TxSize = int64(len(t.Inner.TxPayload()))\n\tt.VM = smart.GetVM()\n\tt.CLB = true\n\tt.Rollback = false\n\tt.SysUpdate = false\n\n\tresultContract, err = t.SmartContract.CallContract(0)\n\treturn\n}\n*/\n"
  },
  {
    "path": "packages/transaction/process.go",
    "content": "package transaction\n\nimport (\n\t\"bytes\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n)\n\nfunc ProcessQueueTransactionBatches(dbTx *sqldb.DbTransaction, qs []*sqldb.QueueTx) error {\n\tvar (\n\t\tcheckTime = time.Now().Unix()\n\t\thashes    [][]byte\n\t\ttrxs      []*sqldb.Transaction\n\t\terr       error\n\t)\n\ttype badTxStruct struct {\n\t\thash  []byte\n\t\tmsg   string\n\t\tkeyID int64\n\t}\n\n\tprocessBadTx := func(dbTx *sqldb.DbTransaction) chan badTxStruct {\n\t\tch := make(chan badTxStruct)\n\n\t\tgo func() {\n\t\t\tfor badTxItem := range ch {\n\t\t\t\tBadTxForBan(badTxItem.keyID)\n\t\t\t\t_ = MarkTransactionBad(badTxItem.hash, badTxItem.msg)\n\t\t\t}\n\t\t}()\n\n\t\treturn ch\n\t}\n\n\ttxBadChan := processBadTx(dbTx)\n\n\tdefer func() {\n\t\tclose(txBadChan)\n\t}()\n\n\tfor i := 0; i < len(qs); i++ {\n\t\ttx := &Transaction{}\n\t\ttx, err = UnmarshallTransaction(bytes.NewBuffer(qs[i].Data), true)\n\t\tif err != nil {\n\t\t\tif tx != nil {\n\t\t\t\ttxBadChan <- badTxStruct{hash: tx.Hash(), msg: err.Error(), keyID: tx.KeyID()}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\terr = tx.Check(checkTime)\n\t\tif err != nil {\n\t\t\ttxBadChan <- badTxStruct{hash: tx.Hash(), msg: err.Error(), keyID: tx.KeyID()}\n\t\t\tcontinue\n\t\t}\n\t\tnewTx := &sqldb.Transaction{\n\t\t\tHash:     tx.Hash(),\n\t\t\tData:     tx.FullData,\n\t\t\tType:     int8(tx.Type()),\n\t\t\tKeyID:    tx.KeyID(),\n\t\t\tExpedite: tx.Expedite(),\n\t\t\tTime:     tx.Timestamp(),\n\t\t\tVerified: 1,\n\t\t\tUsed:     0,\n\t\t\tSent:     0,\n\t\t}\n\t\ttrxs = append(trxs, newTx)\n\t\thashes = append(hashes, qs[i].Hash)\n\t}\n\n\tif len(trxs) > 0 {\n\t\terrTx := sqldb.CreateTransactionBatches(dbTx, trxs)\n\t\tif errTx != nil {\n\t\t\treturn errTx\n\t\t}\n\t}\n\tif len(hashes) > 0 {\n\t\terrQTx := sqldb.DeleteQueueTxs(dbTx, hashes)\n\t\tif errQTx != nil {\n\t\t\treturn errQTx\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/transaction/raw.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/vmihailenco/msgpack/v5\"\n)\n\nfunc (rtx *Transaction) Unmarshall(buffer *bytes.Buffer, fill bool) error {\n\tif buffer.Len() == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"empty transaction buffer\")\n\t\treturn fmt.Errorf(\"empty transaction buffer\")\n\t}\n\trtx.FullData = buffer.Bytes()\n\trtx.InToCxt = &InToCxt{\n\t\tDbTransaction: new(sqldb.DbTransaction),\n\t}\n\ttxT, err := buffer.ReadByte()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar inner TransactionCaller\n\tswitch txT {\n\tcase types.SmartContractTxType, types.TransferSelfTxType, types.UtxoTxType:\n\t\titx := &SmartTransactionParser{\n\t\t\tSmartContract: &smart.SmartContract{TxSmart: new(types.SmartTransaction)},\n\t\t}\n\t\tinner = itx\n\t\tif err = itx.Unmarshal(buffer, fill); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase byte(128): //reset unmarshal client buf\n\t\titx := &SmartTransactionParser{\n\t\t\tSmartContract: &smart.SmartContract{TxSmart: new(types.SmartTransaction)},\n\t\t}\n\t\tinner = itx\n\t\tif err := converter.BinUnmarshalBuff(buffer, &itx.Payload); err != nil {\n\t\t\treturn err\n\t\t}\n\t\titx.Hash = crypto.DoubleHash(itx.Payload)\n\t\titx.TxSignature = buffer.Bytes()\n\t\tif err := msgpack.Unmarshal(itx.Payload, &itx.TxSmart); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar newbuf []byte\n\t\tnewbuf, err = itx.Marshal()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = itx.Unmarshal(bytes.NewBuffer(newbuf), fill); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trtx.FullData = newbuf\n\tcase types.FirstBlockTxType:\n\t\tvar itx FirstBlockParser\n\t\tinner = &itx\n\t\tif err := itx.Unmarshal(buffer); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.UnmarshallingError, \"tx_type\": itx.txType()}).Error(\"getting parser for tx type\")\n\t\t\treturn err\n\t\t}\n\tcase types.StopNetworkTxType:\n\t\tvar itx = StopNetworkParser{}\n\t\tinner = &itx\n\n\t\tif err := itx.Unmarshal(buffer); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.UnmarshallingError, \"tx_type\": rtx.Type()}).Error(\"getting parser for tx type\")\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported tx type %d\", txT)\n\t}\n\trtx.Inner = inner\n\tif cache, ok := txCache.Get(fmt.Sprintf(\"%x\", rtx.Hash())); ok {\n\t\trtx = cache\n\t\treturn nil\n\t}\n\ttxCache.Set(rtx)\n\treturn nil\n}\n\nfunc (rtx *Transaction) SetRawTx() *sqldb.RawTx {\n\treturn &sqldb.RawTx{\n\t\tHash:     rtx.Hash(),\n\t\tTime:     rtx.Timestamp(),\n\t\tTxType:   rtx.Type(),\n\t\tData:     rtx.FullData,\n\t\tExpedite: rtx.Expedite().String(),\n\t\tWalletID: rtx.KeyID(),\n\t}\n}\n"
  },
  {
    "path": "packages/transaction/smart_contract.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/script\"\n\t\"github.com/IBAX-io/go-ibax/packages/smart\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/IBAX-io/go-ibax/packages/utils\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/vmihailenco/msgpack/v5\"\n)\n\ntype SmartTransactionParser struct {\n\t*smart.SmartContract\n}\n\nfunc (s *SmartTransactionParser) txType() byte      { return s.TxSmart.TxType() }\nfunc (s *SmartTransactionParser) txHash() []byte    { return s.Hash }\nfunc (s *SmartTransactionParser) txPayload() []byte { return s.Payload }\nfunc (s *SmartTransactionParser) txTime() int64     { return s.Timestamp }\nfunc (s *SmartTransactionParser) txKeyID() int64    { return s.TxSmart.KeyID }\nfunc (s *SmartTransactionParser) txExpedite() decimal.Decimal {\n\tdec, _ := decimal.NewFromString(s.TxSmart.Expedite)\n\treturn dec\n}\nfunc (s *SmartTransactionParser) setTimestamp() {\n\ts.Timestamp = time.Now().UnixMilli()\n}\n\nfunc (s *SmartTransactionParser) Init(t *InToCxt) error {\n\ts.Rand = t.Rand\n\ts.GenBlock = t.GenBlock\n\ts.BlockHeader = t.BlockHeader\n\ts.PreBlockHeader = t.PreBlockHeader\n\ts.Notifications = t.Notifications\n\ts.DbTransaction = t.DbTransaction\n\ts.TxSize = int64(len(s.Payload))\n\ts.VM = script.GetVM()\n\ts.CLB = false\n\ts.Rollback = true\n\ts.SysUpdate = false\n\ts.OutputsMap = t.OutputsMap\n\ts.PrevSysPar = t.PrevSysPar\n\ts.EcoParams = t.EcoParams\n\ts.TxInputsMap = make(map[sqldb.KeyUTXO][]sqldb.SpentInfo)\n\ts.TxOutputsMap = make(map[sqldb.KeyUTXO][]sqldb.SpentInfo)\n\ts.RollBackTx = make([]*types.RollbackTx, 0)\n\tif s.GenBlock {\n\t\ts.TimeLimit = syspar.GetMaxBlockGenerationTime()\n\t}\n\ts.Key = &sqldb.Key{}\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) Validate() error {\n\tif err := s.TxSmart.Validate(); err != nil {\n\t\treturn err\n\t}\n\t_, err := utils.CheckSign([][]byte{crypto.CutPub(s.TxSmart.PublicKey)}, s.Hash, s.TxSignature, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) Action(in *InToCxt, out *OutCtx) (err error) {\n\tvar res string\n\tdefer func() {\n\t\tif len(res) > 255 {\n\t\t\tres = res[:252] + \"...\"\n\t\t}\n\t\tret := &pbgo.TxResult{\n\t\t\tResult: res,\n\t\t\tHash:   out.TxResult.Hash,\n\t\t}\n\t\tif s.Penalty {\n\t\t\tret.Code = pbgo.TxInvokeStatusCode_PENALTY\n\t\t\tret.BlockId = s.BlockHeader.BlockId\n\t\t}\n\t\tout.Apply(\n\t\t\tWithOutCtxTxResult(ret),\n\t\t\tWithOutCtxSysUpdate(s.SysUpdate),\n\t\t\tWithOutCtxRollBackTx(s.RollBackTx),\n\t\t)\n\t\tif err != nil || s.Penalty {\n\t\t\tif s.FlushRollback != nil {\n\t\t\t\tflush := s.FlushRollback\n\t\t\t\tfor i := len(flush) - 1; i >= 0; i-- {\n\t\t\t\t\tflush[i].FlushVM()\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tret.Code = pbgo.TxInvokeStatusCode_SUCCESS\n\t\tret.BlockId = s.BlockHeader.BlockId\n\t\tout.Apply(\n\t\t\tWithOutCtxTxResult(ret),\n\t\t\tWithOutCtxTxOutputs(s.TxOutputsMap),\n\t\t\tWithOutCtxTxInputs(s.TxInputsMap),\n\t\t)\n\t\t//in.DbTransaction.BinLogSql = s.DbTransaction.BinLogSql\n\t}()\n\n\t_transferSelf := s.TxSmart.TransferSelf\n\tif _transferSelf != nil {\n\t\t_, err = smart.TransferSelf(s.SmartContract, _transferSelf.Value, _transferSelf.Source, _transferSelf.Target)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = in.TxCheckLimits.CheckLimit(s)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\treturn\n\t}\n\t_utxo := s.TxSmart.UTXO\n\tif _utxo != nil {\n\t\t_, err = smart.UtxoToken(s.SmartContract, _utxo.ToID, _utxo.Value)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = in.TxCheckLimits.CheckLimit(s)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\treturn\n\t}\n\tres, err = s.CallContract(in.SqlDbSavePoint)\n\tif err == nil && s.TxSmart != nil {\n\t\terr = in.TxCheckLimits.CheckLimit(s)\n\t}\n\tif err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc (s *SmartTransactionParser) TxRollback() error {\n\treturn syspar.SysUpdate(s.DbTransaction)\n}\n\nfunc (s *SmartTransactionParser) Marshal() ([]byte, error) {\n\ts.setTimestamp()\n\tif err := s.Validate(); err != nil {\n\t\treturn nil, err\n\t}\n\tbuf, err := msgpack.Marshal(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf = append([]byte{s.txType()}, buf...)\n\treturn buf, nil\n}\n\nfunc (s *SmartTransactionParser) setSig(privateKey []byte) error {\n\tsignature, err := crypto.Sign(privateKey, s.Hash)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"signing by node private key\")\n\t\treturn err\n\t}\n\ts.TxSignature = converter.EncodeLengthPlusData(signature)\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) BinMarshalWithPrivate(smartTx *types.SmartTransaction, privateKey []byte, internal bool) ([]byte, error) {\n\tvar (\n\t\tbuf []byte\n\t\terr error\n\t)\n\tif err = smartTx.WithPrivate(privateKey, internal); err != nil {\n\t\treturn nil, err\n\t}\n\ts.TxSmart = smartTx\n\tbuf, err = s.TxSmart.Marshal()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts.Payload = buf\n\ts.Hash = crypto.DoubleHash(s.Payload)\n\terr = s.setSig(privateKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn s.Marshal()\n}\n\nfunc (s *SmartTransactionParser) Unmarshal(buffer *bytes.Buffer, fill bool) error {\n\tbuffer.UnreadByte()\n\tif err := msgpack.Unmarshal(buffer.Bytes()[1:], s); err != nil {\n\t\treturn err\n\t}\n\tif s.SmartContract.TxSmart.UTXO != nil || s.SmartContract.TxSmart.TransferSelf != nil {\n\t\treturn nil\n\t}\n\tif err := s.parseFromContract(fill); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) parseFromContract(fillData bool) error {\n\tvar err error\n\tsmartTx := s.TxSmart\n\tcontract := smart.GetContractByID(int32(smartTx.ID))\n\tif contract == nil {\n\t\tlog.WithFields(log.Fields{\"contract_id\": smartTx.ID, \"type\": consts.NotFound}).Error(\"unknown contract\")\n\t\treturn fmt.Errorf(`unknown contract %d`, smartTx.ID)\n\t}\n\n\ts.TxContract = contract\n\ts.TxData = make(map[string]any)\n\ttxInfo := contract.Info().Tx\n\n\tif txInfo != nil {\n\t\tif fillData {\n\t\t\tfor k := range smartTx.Params {\n\t\t\t\tif _, ok := contract.Info().TxMap()[k]; !ok {\n\t\t\t\t\treturn fmt.Errorf(\"'%s' parameter is not required\", k)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif s.TxData, err = smart.FillTxData(*txInfo, smartTx.Params); err != nil {\n\t\t\t\treturn errors.Wrap(err, fmt.Sprintf(\"contract '%s'\", contract.Name))\n\t\t\t}\n\t\t} else {\n\t\t\ts.TxData = smartTx.Params\n\t\t\tfor key, item := range s.TxData {\n\t\t\t\tif v, ok := item.(map[any]any); ok {\n\t\t\t\t\timap := make(map[string]any)\n\t\t\t\t\tfor ikey, ival := range v {\n\t\t\t\t\t\timap[fmt.Sprint(ikey)] = ival\n\t\t\t\t\t}\n\t\t\t\t\ts.TxData[key] = imap\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) SysUpdateWorker(dbTx *sqldb.DbTransaction) error {\n\tif !s.SysUpdate {\n\t\treturn nil\n\t}\n\tif err := syspar.SysUpdate(dbTx); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating syspar\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) SysTableColByteaWorker(dbTx *sqldb.DbTransaction) error {\n\tif err := syspar.SysTableColType(dbTx); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.DBError, \"error\": err}).Error(\"updating syspar\")\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (s *SmartTransactionParser) FlushVM() {\n\tif s.FlushRollback == nil {\n\t\treturn\n\t}\n\tflush := s.FlushRollback\n\tfor i := len(flush) - 1; i >= 0; i-- {\n\t\tflush[i].FlushVM()\n\t}\n\treturn\n}\n\ntype TxOutCtx struct {\n\tSysUpdate        bool\n\tSysTableColBytea bool\n\tFlush            bool\n\tFlushRollback    []*smart.FlushInfo\n\tVM               *script.VM\n\tVM2              *script.VM\n}\n"
  },
  {
    "path": "packages/transaction/stop_network.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\t\"github.com/vmihailenco/msgpack/v5\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto/x509\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nvar (\n\tmessageNetworkStopping = \"Attention! The network is stopped!\"\n\n\tErrNetworkStopping = errors.New(\"network is stopping\")\n)\n\ntype StopNetworkParser struct {\n\tLogger    *log.Entry\n\tData      *types.StopNetwork\n\tCert      *x509.Cert\n\tTimestamp int64\n\tTxHash    []byte\n\tPayload   []byte // transaction binary data\n}\n\nfunc (s *StopNetworkParser) txType() byte                { return s.Data.TxType() }\nfunc (s *StopNetworkParser) txHash() []byte              { return s.TxHash }\nfunc (s *StopNetworkParser) txPayload() []byte           { return s.Payload }\nfunc (s *StopNetworkParser) txTime() int64               { return s.Timestamp }\nfunc (s *StopNetworkParser) txKeyID() int64              { return s.Data.KeyID }\nfunc (s *StopNetworkParser) txExpedite() decimal.Decimal { return decimal.Decimal{} }\nfunc (s *StopNetworkParser) setTimestamp()               { s.Timestamp = time.Now().UnixMilli() }\n\nfunc (s *StopNetworkParser) Init(in *InToCxt) error {\n\treturn nil\n}\n\nfunc (s *StopNetworkParser) Validate() error {\n\tif err := s.validate(); err != nil {\n\t\ts.Logger.WithError(err).Error(\"validating tx\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *StopNetworkParser) validate() error {\n\tdata := s.Data\n\tcert, err := x509.ParseCert(data.StopNetworkCert)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfbdata, err := syspar.GetFirstBlockData()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = cert.Validate(fbdata.StopNetworkCertBundle); err != nil {\n\t\treturn err\n\t}\n\n\ts.Cert = cert\n\treturn nil\n}\n\nfunc (s *StopNetworkParser) Action(in *InToCxt, out *OutCtx) (err error) {\n\t// Allow execute transaction, if the certificate was used\n\tif s.Cert.EqualBytes(consts.UsedStopNetworkCerts...) {\n\t\treturn nil\n\t}\n\n\t// Set the node in a pause state\n\t//node.PauseNodeActivity(node.PauseTypeStopingNetwork)\n\n\ts.Logger.Warn(messageNetworkStopping)\n\treturn ErrNetworkStopping\n}\n\nfunc (s *StopNetworkParser) TxRollback() error                                      { return nil }\nfunc (s *StopNetworkParser) SysUpdateWorker(dbTx *sqldb.DbTransaction) error        { return nil }\nfunc (s *StopNetworkParser) SysTableColByteaWorker(dbTx *sqldb.DbTransaction) error { return nil }\nfunc (s *StopNetworkParser) FlushVM()                                               {}\n\nfunc (s *StopNetworkParser) BinMarshal(data *types.StopNetwork) ([]byte, error) {\n\ts.setTimestamp()\n\ts.Data = data\n\tvar (\n\t\tbuf []byte\n\t\terr error\n\t)\n\tbuf, err = msgpack.Marshal(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts.Payload = buf\n\ts.TxHash = crypto.DoubleHash(s.Payload)\n\n\terr = s.validate()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf, err = msgpack.Marshal(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf = append([]byte{s.txType()}, buf...)\n\treturn buf, nil\n}\n\nfunc (s *StopNetworkParser) Unmarshal(buffer *bytes.Buffer) error {\n\tbuffer.UnreadByte()\n\tif err := msgpack.Unmarshal(buffer.Bytes()[1:], s); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/transaction/transaction.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage transaction\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math/rand\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n\t\"github.com/shopspring/decimal\"\n)\n\n// Transaction is a structure for parsing transactions\ntype Transaction struct {\n\tFullData []byte // full transaction, with type and data\n\t*InToCxt\n\t*OutCtx\n\tInner TransactionCaller\n}\n\n// TransactionCaller is parsing transactions\ntype TransactionCaller interface {\n\tInit(*InToCxt) error\n\tValidate() error\n\tAction(*InToCxt, *OutCtx) error\n\tTxRollback() error\n\ttxType() byte\n\ttxHash() []byte\n\ttxPayload() []byte\n\ttxTime() int64\n\ttxKeyID() int64\n\ttxExpedite() decimal.Decimal\n}\n\nfunc (t *Transaction) Type() byte                { return t.Inner.txType() }\nfunc (t *Transaction) Hash() []byte              { return t.Inner.txHash() }\nfunc (t *Transaction) Payload() []byte           { return t.Inner.txPayload() }\nfunc (t *Transaction) Timestamp() int64          { return t.Inner.txTime() }\nfunc (t *Transaction) KeyID() int64              { return t.Inner.txKeyID() }\nfunc (t *Transaction) Expedite() decimal.Decimal { return t.Inner.txExpedite() }\n\nfunc (t *Transaction) IsSmartContract() bool {\n\t_, ok := t.Inner.(*SmartTransactionParser)\n\treturn ok\n}\n\nfunc (t *Transaction) SmartContract() *SmartTransactionParser {\n\treturn t.Inner.(*SmartTransactionParser)\n}\n\n// UnmarshallTransaction is unmarshalling transaction\nfunc UnmarshallTransaction(buffer *bytes.Buffer, fill bool) (*Transaction, error) {\n\ttx := &Transaction{}\n\tvar err error\n\tdefer func() {\n\t\tif err != nil && tx != nil {\n\t\t\tif tx.Inner == nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t_ = MarkTransactionBad(tx.Hash(), err.Error())\n\t\t}\n\t}()\n\terr = tx.Unmarshall(buffer, fill)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse transaction error: %w\", err)\n\t}\n\treturn tx, nil\n}\n\nfunc (tr *Transaction) WithOption(\n\tnotifications types.Notifications,\n\tgenBlock bool,\n\tblockHeader, preBlockHeader *types.BlockHeader,\n\tdbTransaction *sqldb.DbTransaction,\n\trand *rand.Rand,\n\ttxCheckLimits *Limits,\n\tsqlDbSavePoint string,\n\toutputsMap map[sqldb.KeyUTXO][]sqldb.SpentInfo,\n\tprevSysPar map[string]string,\n\tecoParams []sqldb.EcoParam,\n\topts ...TransactionOption) error {\n\tin := &InToCxt{\n\t\tSqlDbSavePoint: sqlDbSavePoint,\n\t\tTxCheckLimits:  txCheckLimits,\n\t\tRand:           rand,\n\t\tDbTransaction:  dbTransaction,\n\t\tPreBlockHeader: preBlockHeader,\n\t\tBlockHeader:    blockHeader,\n\t\tGenBlock:       genBlock,\n\t\tNotifications:  notifications,\n\t\tOutputsMap:     outputsMap,\n\t\tPrevSysPar:     prevSysPar,\n\t\tEcoParams:      ecoParams,\n\t}\n\tin.DbTransaction.BinLogSql = nil\n\ttr.InToCxt = in\n\ttr.OutCtx = &OutCtx{\n\t\tTxResult: &pbgo.TxResult{Hash: tr.Hash()},\n\t}\n\treturn tr.Apply(opts...)\n}\n\ntype TransactionOption func(b *Transaction) error\n\nfunc (tr *Transaction) Apply(opts ...TransactionOption) error {\n\tfor _, opt := range opts {\n\t\tif opt == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif err := opt(tr); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/types/api.go",
    "content": "package types\n\nimport log \"github.com/sirupsen/logrus\"\n\ntype EcosystemGetter interface {\n\tGetEcosystemLookup() ([]int64, []string, error)\n\tValidateId(id, clientID int64, le *log.Entry) (int64, error)\n\tGetEcosystemName(id int64) (string, error)\n}\n"
  },
  {
    "path": "packages/types/block.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: block.proto\n\npackage types\n\nimport (\n\tfmt \"fmt\"\n\tproto \"github.com/gogo/protobuf/proto\"\n\tio \"io\"\n\tmath \"math\"\n\tmath_bits \"math/bits\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package\n\n// BlockSyncMethod define block sync method.\ntype BlockSyncMethod int32\n\nconst (\n\tBlockSyncMethod_CONTRACTVM BlockSyncMethod = 0\n\tBlockSyncMethod_SQLDML     BlockSyncMethod = 1\n)\n\nvar BlockSyncMethod_name = map[int32]string{\n\t0: \"CONTRACTVM\",\n\t1: \"SQLDML\",\n}\n\nvar BlockSyncMethod_value = map[string]int32{\n\t\"CONTRACTVM\": 0,\n\t\"SQLDML\":     1,\n}\n\nfunc (x BlockSyncMethod) String() string {\n\treturn proto.EnumName(BlockSyncMethod_name, int32(x))\n}\n\nfunc (BlockSyncMethod) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_8e550b1f5926e92d, []int{0}\n}\n\n//BlockHeader is a structure of the block's header\ntype BlockHeader struct {\n\tBlockId      int64  `protobuf:\"varint,1,opt,name=block_id,json=blockId,proto3\" json:\"block_id,omitempty\"`\n\tTimestamp    int64  `protobuf:\"varint,2,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\tEcosystemId  int64  `protobuf:\"varint,3,opt,name=ecosystem_id,json=ecosystemId,proto3\" json:\"ecosystem_id,omitempty\"`\n\tKeyId        int64  `protobuf:\"varint,4,opt,name=key_id,json=keyId,proto3\" json:\"key_id,omitempty\"`\n\tNodePosition int64  `protobuf:\"varint,5,opt,name=node_position,json=nodePosition,proto3\" json:\"node_position,omitempty\"`\n\tSign         []byte `protobuf:\"bytes,6,opt,name=sign,proto3\" json:\"sign,omitempty\"`\n\tBlockHash    []byte `protobuf:\"bytes,7,opt,name=block_hash,json=blockHash,proto3\" json:\"block_hash,omitempty\"`\n\t//differences with before and after in tx modification table\n\tRollbacksHash  []byte `protobuf:\"bytes,8,opt,name=rollbacks_hash,json=rollbacksHash,proto3\" json:\"rollbacks_hash,omitempty\"`\n\tVersion        int32  `protobuf:\"varint,9,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tConsensusMode  int32  `protobuf:\"varint,10,opt,name=consensus_mode,json=consensusMode,proto3\" json:\"consensus_mode,omitempty\"`\n\tCandidateNodes []byte `protobuf:\"bytes,11,opt,name=candidate_nodes,json=candidateNodes,proto3\" json:\"candidate_nodes,omitempty\"`\n\tNetworkId      int64  `protobuf:\"varint,12,opt,name=network_id,json=networkId,proto3\" json:\"network_id,omitempty\"`\n}\n\nfunc (m *BlockHeader) Reset()         { *m = BlockHeader{} }\nfunc (m *BlockHeader) String() string { return proto.CompactTextString(m) }\nfunc (*BlockHeader) ProtoMessage()    {}\nfunc (*BlockHeader) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_8e550b1f5926e92d, []int{0}\n}\nfunc (m *BlockHeader) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *BlockHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_BlockHeader.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *BlockHeader) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_BlockHeader.Merge(m, src)\n}\nfunc (m *BlockHeader) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *BlockHeader) XXX_DiscardUnknown() {\n\txxx_messageInfo_BlockHeader.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_BlockHeader proto.InternalMessageInfo\n\nfunc (m *BlockHeader) GetBlockId() int64 {\n\tif m != nil {\n\t\treturn m.BlockId\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetTimestamp() int64 {\n\tif m != nil {\n\t\treturn m.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetEcosystemId() int64 {\n\tif m != nil {\n\t\treturn m.EcosystemId\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetKeyId() int64 {\n\tif m != nil {\n\t\treturn m.KeyId\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetNodePosition() int64 {\n\tif m != nil {\n\t\treturn m.NodePosition\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetSign() []byte {\n\tif m != nil {\n\t\treturn m.Sign\n\t}\n\treturn nil\n}\n\nfunc (m *BlockHeader) GetBlockHash() []byte {\n\tif m != nil {\n\t\treturn m.BlockHash\n\t}\n\treturn nil\n}\n\nfunc (m *BlockHeader) GetRollbacksHash() []byte {\n\tif m != nil {\n\t\treturn m.RollbacksHash\n\t}\n\treturn nil\n}\n\nfunc (m *BlockHeader) GetVersion() int32 {\n\tif m != nil {\n\t\treturn m.Version\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetConsensusMode() int32 {\n\tif m != nil {\n\t\treturn m.ConsensusMode\n\t}\n\treturn 0\n}\n\nfunc (m *BlockHeader) GetCandidateNodes() []byte {\n\tif m != nil {\n\t\treturn m.CandidateNodes\n\t}\n\treturn nil\n}\n\nfunc (m *BlockHeader) GetNetworkId() int64 {\n\tif m != nil {\n\t\treturn m.NetworkId\n\t}\n\treturn 0\n}\n\n// BlockData is a structure of the block's\ntype BlockData struct {\n\tHeader     *BlockHeader `protobuf:\"bytes,1,opt,name=header,proto3\" json:\"header,omitempty\"`\n\tPrevHeader *BlockHeader `protobuf:\"bytes,2,opt,name=prev_header,json=prevHeader,proto3\" json:\"prev_header,omitempty\"`\n\tMerkleRoot []byte       `protobuf:\"bytes,3,opt,name=merkle_root,json=merkleRoot,proto3\" json:\"merkle_root,omitempty\"`\n\tBinData    []byte       `protobuf:\"bytes,4,opt,name=bin_data,json=binData,proto3\" json:\"bin_data,omitempty\"`\n\tTxFullData [][]byte     `protobuf:\"bytes,5,rep,name=tx_full_data,json=txFullData,proto3\" json:\"tx_full_data,omitempty\"`\n\tAfterTxs   *AfterTxs    `protobuf:\"bytes,6,opt,name=after_txs,json=afterTxs,proto3\" json:\"after_txs,omitempty\"`\n\tSysUpdate  bool         `protobuf:\"varint,7,opt,name=sys_update,json=sysUpdate,proto3\" json:\"sys_update,omitempty\"`\n}\n\nfunc (m *BlockData) Reset()         { *m = BlockData{} }\nfunc (m *BlockData) String() string { return proto.CompactTextString(m) }\nfunc (*BlockData) ProtoMessage()    {}\nfunc (*BlockData) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_8e550b1f5926e92d, []int{1}\n}\nfunc (m *BlockData) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *BlockData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_BlockData.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *BlockData) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_BlockData.Merge(m, src)\n}\nfunc (m *BlockData) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *BlockData) XXX_DiscardUnknown() {\n\txxx_messageInfo_BlockData.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_BlockData proto.InternalMessageInfo\n\nfunc (m *BlockData) GetHeader() *BlockHeader {\n\tif m != nil {\n\t\treturn m.Header\n\t}\n\treturn nil\n}\n\nfunc (m *BlockData) GetPrevHeader() *BlockHeader {\n\tif m != nil {\n\t\treturn m.PrevHeader\n\t}\n\treturn nil\n}\n\nfunc (m *BlockData) GetMerkleRoot() []byte {\n\tif m != nil {\n\t\treturn m.MerkleRoot\n\t}\n\treturn nil\n}\n\nfunc (m *BlockData) GetBinData() []byte {\n\tif m != nil {\n\t\treturn m.BinData\n\t}\n\treturn nil\n}\n\nfunc (m *BlockData) GetTxFullData() [][]byte {\n\tif m != nil {\n\t\treturn m.TxFullData\n\t}\n\treturn nil\n}\n\nfunc (m *BlockData) GetAfterTxs() *AfterTxs {\n\tif m != nil {\n\t\treturn m.AfterTxs\n\t}\n\treturn nil\n}\n\nfunc (m *BlockData) GetSysUpdate() bool {\n\tif m != nil {\n\t\treturn m.SysUpdate\n\t}\n\treturn false\n}\n\nfunc init() {\n\tproto.RegisterEnum(\"types.BlockSyncMethod\", BlockSyncMethod_name, BlockSyncMethod_value)\n\tproto.RegisterType((*BlockHeader)(nil), \"types.BlockHeader\")\n\tproto.RegisterType((*BlockData)(nil), \"types.BlockData\")\n}\n\nfunc init() { proto.RegisterFile(\"block.proto\", fileDescriptor_8e550b1f5926e92d) }\n\nvar fileDescriptor_8e550b1f5926e92d = []byte{\n\t// 554 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0xcd, 0x6e, 0xd3, 0x40,\n\t0x14, 0x85, 0xe3, 0xa6, 0xf9, 0xf1, 0xb5, 0xfb, 0xa3, 0x91, 0x90, 0x0c, 0x02, 0x13, 0x8a, 0x10,\n\t0xa5, 0xa2, 0x89, 0xd4, 0x3e, 0x41, 0x9b, 0x0a, 0x35, 0x52, 0x53, 0xc0, 0x0d, 0x08, 0xb1, 0xb1,\n\t0xc6, 0x9e, 0x69, 0x6c, 0xf9, 0x67, 0x2c, 0xcf, 0xa4, 0xc4, 0x6f, 0xc0, 0x92, 0x1d, 0xaf, 0xc4,\n\t0xb2, 0x4b, 0x96, 0x28, 0x79, 0x11, 0x34, 0xd7, 0x26, 0xb0, 0x61, 0x37, 0xf3, 0x9d, 0x73, 0x33,\n\t0x27, 0xf7, 0x24, 0x60, 0x05, 0xa9, 0x08, 0x93, 0x61, 0x51, 0x0a, 0x25, 0x48, 0x47, 0x55, 0x05,\n\t0x97, 0x8f, 0xa0, 0x48, 0x69, 0x55, 0xa3, 0x83, 0xaf, 0x6d, 0xb0, 0xce, 0xb5, 0xe5, 0x92, 0x53,\n\t0xc6, 0x4b, 0xf2, 0x10, 0xfa, 0x38, 0xe1, 0xc7, 0xcc, 0x31, 0x06, 0xc6, 0x61, 0xdb, 0xeb, 0xe1,\n\t0x7d, 0xc2, 0xc8, 0x63, 0x30, 0x55, 0x9c, 0x71, 0xa9, 0x68, 0x56, 0x38, 0x5b, 0xa8, 0xfd, 0x05,\n\t0xe4, 0x19, 0xd8, 0x3c, 0x14, 0xb2, 0x92, 0x8a, 0x67, 0x7a, 0xb8, 0x8d, 0x06, 0x6b, 0xc3, 0x26,\n\t0x8c, 0x3c, 0x80, 0x6e, 0xc2, 0x2b, 0x2d, 0x6e, 0xa3, 0xd8, 0x49, 0x78, 0x35, 0x61, 0xe4, 0x39,\n\t0xec, 0xe4, 0x82, 0x71, 0xbf, 0x10, 0x32, 0x56, 0xb1, 0xc8, 0x9d, 0x0e, 0xaa, 0xb6, 0x86, 0xef,\n\t0x1a, 0x46, 0x08, 0x6c, 0xcb, 0x78, 0x9e, 0x3b, 0xdd, 0x81, 0x71, 0x68, 0x7b, 0x78, 0x26, 0x4f,\n\t0x00, 0xea, 0xac, 0x11, 0x95, 0x91, 0xd3, 0x43, 0xc5, 0x44, 0x72, 0x49, 0x65, 0x44, 0x5e, 0xc0,\n\t0x6e, 0x29, 0xd2, 0x34, 0xa0, 0x61, 0x22, 0x6b, 0x4b, 0x1f, 0x2d, 0x3b, 0x1b, 0x8a, 0x36, 0x07,\n\t0x7a, 0x77, 0xbc, 0x94, 0xfa, 0x61, 0x73, 0x60, 0x1c, 0x76, 0xbc, 0x3f, 0x57, 0xfd, 0x01, 0xa1,\n\t0xc8, 0x25, 0xcf, 0xe5, 0x42, 0xfa, 0x99, 0x60, 0xdc, 0x01, 0x34, 0xec, 0x6c, 0xe8, 0x54, 0x30,\n\t0x4e, 0x5e, 0xc2, 0x5e, 0x48, 0x73, 0x16, 0x33, 0xaa, 0xb8, 0xaf, 0x43, 0x4b, 0xc7, 0xc2, 0x87,\n\t0x76, 0x37, 0xf8, 0x5a, 0x53, 0x9d, 0x37, 0xe7, 0xea, 0x8b, 0x28, 0x71, 0xbb, 0x76, 0xbd, 0xc1,\n\t0x86, 0x4c, 0xd8, 0xc1, 0xf7, 0x2d, 0x30, 0xb1, 0x8a, 0x0b, 0xaa, 0x28, 0x39, 0x82, 0x6e, 0x84,\n\t0x95, 0x60, 0x0d, 0xd6, 0x09, 0x19, 0x62, 0x79, 0xc3, 0x7f, 0xca, 0xf2, 0x1a, 0x07, 0x39, 0x05,\n\t0xab, 0x28, 0xf9, 0x9d, 0xdf, 0x0c, 0x6c, 0xfd, 0x77, 0x00, 0xb4, 0xad, 0x69, 0xfa, 0x29, 0x58,\n\t0x19, 0x2f, 0x93, 0x94, 0xfb, 0xa5, 0x10, 0x0a, 0xfb, 0xb2, 0x3d, 0xa8, 0x91, 0x27, 0x84, 0xc2,\n\t0x9f, 0x42, 0x9c, 0xfb, 0x8c, 0x2a, 0x8a, 0x85, 0xd9, 0x5e, 0x2f, 0x88, 0x73, 0x0c, 0x37, 0x00,\n\t0x5b, 0x2d, 0xfd, 0xdb, 0x45, 0x9a, 0xd6, 0x72, 0x67, 0xd0, 0xd6, 0xc3, 0x6a, 0xf9, 0x66, 0x91,\n\t0xa6, 0xe8, 0x78, 0x0d, 0x26, 0xbd, 0x55, 0xbc, 0xf4, 0xd5, 0x52, 0x62, 0x69, 0xd6, 0xc9, 0x5e,\n\t0x13, 0xe8, 0x4c, 0xf3, 0xd9, 0x52, 0x7a, 0x7d, 0xda, 0x9c, 0xf4, 0x66, 0x64, 0x25, 0xfd, 0x45,\n\t0xa1, 0x97, 0x85, 0x4d, 0xf6, 0x3d, 0x53, 0x56, 0xf2, 0x03, 0x82, 0xa3, 0x63, 0xd8, 0xc3, 0x6f,\n\t0x71, 0x53, 0xe5, 0xe1, 0x94, 0xab, 0x48, 0x30, 0xb2, 0x0b, 0x30, 0x7e, 0x7b, 0x3d, 0xf3, 0xce,\n\t0xc6, 0xb3, 0x8f, 0xd3, 0xfd, 0x16, 0x01, 0xe8, 0xde, 0xbc, 0xbf, 0xba, 0x98, 0x5e, 0xed, 0x1b,\n\t0xe7, 0xe3, 0x1f, 0x2b, 0xd7, 0xb8, 0x5f, 0xb9, 0xc6, 0xaf, 0x95, 0x6b, 0x7c, 0x5b, 0xbb, 0xad,\n\t0xfb, 0xb5, 0xdb, 0xfa, 0xb9, 0x76, 0x5b, 0x9f, 0x5f, 0xcd, 0x63, 0x15, 0x2d, 0x82, 0x61, 0x28,\n\t0xb2, 0xd1, 0xe4, 0xfc, 0xec, 0xd3, 0x71, 0x2c, 0x46, 0x73, 0x71, 0x1c, 0x07, 0x74, 0x39, 0x2a,\n\t0x68, 0x98, 0xd0, 0x39, 0x97, 0x23, 0x4c, 0x19, 0x74, 0xf1, 0xff, 0x71, 0xfa, 0x3b, 0x00, 0x00,\n\t0xff, 0xff, 0x6d, 0xf2, 0x4f, 0x4d, 0x41, 0x03, 0x00, 0x00,\n}\n\nfunc (m *BlockHeader) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BlockHeader) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *BlockHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.NetworkId != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.NetworkId))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif len(m.CandidateNodes) > 0 {\n\t\ti -= len(m.CandidateNodes)\n\t\tcopy(dAtA[i:], m.CandidateNodes)\n\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.CandidateNodes)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif m.ConsensusMode != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.ConsensusMode))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Version != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.Version))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif len(m.RollbacksHash) > 0 {\n\t\ti -= len(m.RollbacksHash)\n\t\tcopy(dAtA[i:], m.RollbacksHash)\n\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.RollbacksHash)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.BlockHash) > 0 {\n\t\ti -= len(m.BlockHash)\n\t\tcopy(dAtA[i:], m.BlockHash)\n\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.BlockHash)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.Sign) > 0 {\n\t\ti -= len(m.Sign)\n\t\tcopy(dAtA[i:], m.Sign)\n\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.Sign)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.NodePosition != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.NodePosition))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.KeyId != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.KeyId))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.EcosystemId != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.EcosystemId))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Timestamp != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.Timestamp))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.BlockId != 0 {\n\t\ti = encodeVarintBlock(dAtA, i, uint64(m.BlockId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BlockData) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BlockData) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *BlockData) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.SysUpdate {\n\t\ti--\n\t\tif m.SysUpdate {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.AfterTxs != nil {\n\t\t{\n\t\t\tsize, err := m.AfterTxs.MarshalToSizedBuffer(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = encodeVarintBlock(dAtA, i, uint64(size))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.TxFullData) > 0 {\n\t\tfor iNdEx := len(m.TxFullData) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.TxFullData[iNdEx])\n\t\t\tcopy(dAtA[i:], m.TxFullData[iNdEx])\n\t\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.TxFullData[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.BinData) > 0 {\n\t\ti -= len(m.BinData)\n\t\tcopy(dAtA[i:], m.BinData)\n\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.BinData)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.MerkleRoot) > 0 {\n\t\ti -= len(m.MerkleRoot)\n\t\tcopy(dAtA[i:], m.MerkleRoot)\n\t\ti = encodeVarintBlock(dAtA, i, uint64(len(m.MerkleRoot)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.PrevHeader != nil {\n\t\t{\n\t\t\tsize, err := m.PrevHeader.MarshalToSizedBuffer(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = encodeVarintBlock(dAtA, i, uint64(size))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Header != nil {\n\t\t{\n\t\t\tsize, err := m.Header.MarshalToSizedBuffer(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = encodeVarintBlock(dAtA, i, uint64(size))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc encodeVarintBlock(dAtA []byte, offset int, v uint64) int {\n\toffset -= sovBlock(v)\n\tbase := offset\n\tfor v >= 1<<7 {\n\t\tdAtA[offset] = uint8(v&0x7f | 0x80)\n\t\tv >>= 7\n\t\toffset++\n\t}\n\tdAtA[offset] = uint8(v)\n\treturn base\n}\nfunc (m *BlockHeader) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.BlockId != 0 {\n\t\tn += 1 + sovBlock(uint64(m.BlockId))\n\t}\n\tif m.Timestamp != 0 {\n\t\tn += 1 + sovBlock(uint64(m.Timestamp))\n\t}\n\tif m.EcosystemId != 0 {\n\t\tn += 1 + sovBlock(uint64(m.EcosystemId))\n\t}\n\tif m.KeyId != 0 {\n\t\tn += 1 + sovBlock(uint64(m.KeyId))\n\t}\n\tif m.NodePosition != 0 {\n\t\tn += 1 + sovBlock(uint64(m.NodePosition))\n\t}\n\tl = len(m.Sign)\n\tif l > 0 {\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tl = len(m.BlockHash)\n\tif l > 0 {\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tl = len(m.RollbacksHash)\n\tif l > 0 {\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tif m.Version != 0 {\n\t\tn += 1 + sovBlock(uint64(m.Version))\n\t}\n\tif m.ConsensusMode != 0 {\n\t\tn += 1 + sovBlock(uint64(m.ConsensusMode))\n\t}\n\tl = len(m.CandidateNodes)\n\tif l > 0 {\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tif m.NetworkId != 0 {\n\t\tn += 1 + sovBlock(uint64(m.NetworkId))\n\t}\n\treturn n\n}\n\nfunc (m *BlockData) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Header != nil {\n\t\tl = m.Header.Size()\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tif m.PrevHeader != nil {\n\t\tl = m.PrevHeader.Size()\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tl = len(m.MerkleRoot)\n\tif l > 0 {\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tl = len(m.BinData)\n\tif l > 0 {\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tif len(m.TxFullData) > 0 {\n\t\tfor _, b := range m.TxFullData {\n\t\t\tl = len(b)\n\t\t\tn += 1 + l + sovBlock(uint64(l))\n\t\t}\n\t}\n\tif m.AfterTxs != nil {\n\t\tl = m.AfterTxs.Size()\n\t\tn += 1 + l + sovBlock(uint64(l))\n\t}\n\tif m.SysUpdate {\n\t\tn += 2\n\t}\n\treturn n\n}\n\nfunc sovBlock(x uint64) (n int) {\n\treturn (math_bits.Len64(x|1) + 6) / 7\n}\nfunc sozBlock(x uint64) (n int) {\n\treturn sovBlock(uint64((x << 1) ^ uint64((int64(x) >> 63))))\n}\nfunc (m *BlockHeader) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BlockHeader: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BlockHeader: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockId\", wireType)\n\t\t\t}\n\t\t\tm.BlockId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BlockId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timestamp\", wireType)\n\t\t\t}\n\t\t\tm.Timestamp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timestamp |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EcosystemId\", wireType)\n\t\t\t}\n\t\t\tm.EcosystemId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.EcosystemId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KeyId\", wireType)\n\t\t\t}\n\t\t\tm.KeyId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.KeyId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodePosition\", wireType)\n\t\t\t}\n\t\t\tm.NodePosition = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NodePosition |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Sign\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Sign = append(m.Sign[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Sign == nil {\n\t\t\t\tm.Sign = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockHash\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BlockHash = append(m.BlockHash[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.BlockHash == nil {\n\t\t\t\tm.BlockHash = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RollbacksHash\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RollbacksHash = append(m.RollbacksHash[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.RollbacksHash == nil {\n\t\t\t\tm.RollbacksHash = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tm.Version = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Version |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConsensusMode\", wireType)\n\t\t\t}\n\t\t\tm.ConsensusMode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConsensusMode |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CandidateNodes\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CandidateNodes = append(m.CandidateNodes[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.CandidateNodes == nil {\n\t\t\t\tm.CandidateNodes = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NetworkId\", wireType)\n\t\t\t}\n\t\t\tm.NetworkId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NetworkId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipBlock(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BlockData) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BlockData: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BlockData: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Header\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Header == nil {\n\t\t\t\tm.Header = &BlockHeader{}\n\t\t\t}\n\t\t\tif err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrevHeader\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.PrevHeader == nil {\n\t\t\t\tm.PrevHeader = &BlockHeader{}\n\t\t\t}\n\t\t\tif err := m.PrevHeader.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MerkleRoot\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MerkleRoot = append(m.MerkleRoot[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.MerkleRoot == nil {\n\t\t\t\tm.MerkleRoot = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BinData\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BinData = append(m.BinData[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.BinData == nil {\n\t\t\t\tm.BinData = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxFullData\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TxFullData = append(m.TxFullData, make([]byte, postIndex-iNdEx))\n\t\t\tcopy(m.TxFullData[len(m.TxFullData)-1], dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AfterTxs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.AfterTxs == nil {\n\t\t\t\tm.AfterTxs = &AfterTxs{}\n\t\t\t}\n\t\t\tif err := m.AfterTxs.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SysUpdate\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SysUpdate = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipBlock(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc skipBlock(dAtA []byte) (n int, err error) {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tdepth := 0\n\tfor iNdEx < l {\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn 0, ErrIntOverflowBlock\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= (uint64(b) & 0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\twireType := int(wire & 0x7)\n\t\tswitch wireType {\n\t\tcase 0:\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tiNdEx++\n\t\t\t\tif dAtA[iNdEx-1] < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 1:\n\t\t\tiNdEx += 8\n\t\tcase 2:\n\t\t\tvar length int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowBlock\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tlength |= (int(b) & 0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif length < 0 {\n\t\t\t\treturn 0, ErrInvalidLengthBlock\n\t\t\t}\n\t\t\tiNdEx += length\n\t\tcase 3:\n\t\t\tdepth++\n\t\tcase 4:\n\t\t\tif depth == 0 {\n\t\t\t\treturn 0, ErrUnexpectedEndOfGroupBlock\n\t\t\t}\n\t\t\tdepth--\n\t\tcase 5:\n\t\t\tiNdEx += 4\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"proto: illegal wireType %d\", wireType)\n\t\t}\n\t\tif iNdEx < 0 {\n\t\t\treturn 0, ErrInvalidLengthBlock\n\t\t}\n\t\tif depth == 0 {\n\t\t\treturn iNdEx, nil\n\t\t}\n\t}\n\treturn 0, io.ErrUnexpectedEOF\n}\n\nvar (\n\tErrInvalidLengthBlock        = fmt.Errorf(\"proto: negative length found during unmarshaling\")\n\tErrIntOverflowBlock          = fmt.Errorf(\"proto: integer overflow\")\n\tErrUnexpectedEndOfGroupBlock = fmt.Errorf(\"proto: unexpected end of group\")\n)\n"
  },
  {
    "path": "packages/types/block_data.go",
    "content": "package types\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/gogo/protobuf/proto\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/pkg/errors\"\n)\n\nconst (\n\tminBlockSize = 9\n)\n\nvar (\n\tErrMaxBlockSize = func(max int64, size int) error {\n\t\treturn fmt.Errorf(\"block size exceeds maximum %d limit, size is %d\", max, size)\n\t}\n\tErrMinBlockSize = func(min int, size int) error {\n\t\treturn fmt.Errorf(\"block size exceeds minimum %d limit, size is %d\", min, size)\n\t}\n\tErrZeroBlockSize   = errors.New(\"Block size is zero\")\n\tErrUnmarshallBlock = errors.New(\"Unmarshall block\")\n)\n\nfunc blockVer(cur, prev *BlockHeader) (ret string) {\n\tif cur.Version >= consts.BvRollbackHash {\n\t\tret = fmt.Sprintf(\",%x\", prev.RollbacksHash)\n\t}\n\treturn\n}\n\nfunc (b *BlockHeader) GenHash(prev *BlockHeader, mrklRoot []byte) []byte {\n\treturn crypto.DoubleHash([]byte(b.ForSha(prev, mrklRoot)))\n}\n\nfunc (b *BlockHeader) ForSha(prev *BlockHeader, mrklRoot []byte) string {\n\treturn fmt.Sprintf(\"%d,%x,%s,%d,%d,%d,%d,%d\",\n\t\tb.BlockId, prev.BlockHash, mrklRoot, b.Timestamp, b.EcosystemId, b.KeyId, b.NodePosition, b.NetworkId) +\n\t\tblockVer(b, prev)\n}\n\n// ForSign from 128 bytes to 512 bytes. Signature of TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, WALLET_ID, state_id, MRKL_ROOT\nfunc (b *BlockHeader) ForSign(prev *BlockHeader, mrklRoot []byte) string {\n\treturn fmt.Sprintf(\"0,%v,%x,%v,%v,%v,%v,%s,%d\",\n\t\tb.BlockId, prev.BlockHash, b.Timestamp, b.EcosystemId, b.KeyId, b.NodePosition, mrklRoot, b.NetworkId) +\n\t\tblockVer(b, prev)\n}\n\n// ParseBlockHeader is parses block header\nfunc ParseBlockHeader(buf *bytes.Buffer, maxBlockSize int64) (header *BlockHeader, err error) {\n\tif int64(buf.Len()) > maxBlockSize {\n\t\terr = ErrMaxBlockSize(maxBlockSize, buf.Len())\n\t\treturn\n\t}\n\tblo := &BlockData{}\n\tif err := blo.UnmarshallBlock(buf.Bytes()); err != nil {\n\t\treturn nil, err\n\t}\n\treturn blo.Header, nil\n}\n\ntype BlockDataOption func(b *BlockData) error\n\nfunc (b *BlockData) Apply(opts ...BlockDataOption) error {\n\tfor _, opt := range opts {\n\t\tif opt == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif err := opt(b); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc WithCurHeader(cur *BlockHeader) BlockDataOption {\n\treturn func(b *BlockData) error {\n\t\tb.Header = cur\n\t\treturn nil\n\t}\n}\n\nfunc WithPrevHeader(pre *BlockHeader) BlockDataOption {\n\treturn func(b *BlockData) error {\n\t\tb.PrevHeader = pre\n\t\treturn nil\n\t}\n}\n\nfunc WithTxFullData(data [][]byte) BlockDataOption {\n\treturn func(b *BlockData) error {\n\t\tb.TxFullData = data\n\t\treturn nil\n\t}\n}\n\nfunc WithAfterTxs(a *AfterTxs) BlockDataOption {\n\treturn func(b *BlockData) error {\n\t\tb.AfterTxs = a\n\t\treturn nil\n\t}\n}\nfunc WithSysUpdate(a bool) BlockDataOption {\n\treturn func(b *BlockData) error {\n\t\tb.SysUpdate = a\n\t\treturn nil\n\t}\n}\n\nfunc (b BlockData) ForSign() string {\n\treturn b.Header.ForSign(b.PrevHeader, b.MerkleRoot)\n}\n\nfunc (b *BlockData) GenMerkleRoot() []byte {\n\tvar mrklArray [][]byte\n\tfor _, tr := range b.TxFullData {\n\t\tmrklArray = append(mrklArray, converter.BinToHex(crypto.DoubleHash(tr)))\n\t}\n\tif len(mrklArray) == 0 {\n\t\tmrklArray = append(mrklArray, []byte(\"0\"))\n\t}\n\treturn MerkleTreeRoot(mrklArray)\n}\n\nfunc (b *BlockData) GetSign(key []byte) ([]byte, error) {\n\tforSign := b.ForSign()\n\tsigned, err := crypto.Sign(key, []byte(forSign))\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"signing block\")\n\t}\n\treturn signed, nil\n}\n\n// MarshallBlock is marshalling block\nfunc (b *BlockData) MarshallBlock(key []byte) ([]byte, error) {\n\t//if b.AfterTxs != nil {\n\t//\tfor i := 0; i < len(b.AfterTxs.TxBinLogSql); i++ {\n\t//\t\tb.AfterTxs.TxBinLogSql[i] = DoZlibCompress(b.AfterTxs.TxBinLogSql[i])\n\t//\t}\n\t//}\n\tfor i := 0; i < len(b.TxFullData); i++ {\n\t\tb.TxFullData[i] = DoZlibCompress(b.TxFullData[i])\n\t}\n\tb.MerkleRoot = b.GenMerkleRoot()\n\tsigned, err := b.GetSign(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tb.Header.Sign = signed\n\tb.Header.BlockHash = b.Header.GenHash(b.PrevHeader, b.MerkleRoot)\n\treturn proto.Marshal(b)\n}\n\nfunc (b *BlockData) UnmarshallBlock(data []byte) error {\n\tif len(data) == 0 {\n\t\treturn ErrZeroBlockSize\n\t}\n\tif len(data) < minBlockSize {\n\t\treturn ErrMinBlockSize(len(data), minBlockSize)\n\t}\n\tif err := proto.Unmarshal(data, b); err != nil {\n\t\treturn errors.Wrap(err, \"unmarshalling block\")\n\t}\n\t//if b.AfterTxs != nil {\n\t//\tfor i := 0; i < len(b.AfterTxs.TxBinLogSql); i++ {\n\t//\t\tb.AfterTxs.TxBinLogSql[i] = DoZlibUnCompress(b.AfterTxs.TxBinLogSql[i])\n\t//\t}\n\t//}\n\tfor i := 0; i < len(b.TxFullData); i++ {\n\t\tb.TxFullData[i] = DoZlibUnCompress(b.TxFullData[i])\n\t}\n\tb.BinData = data\n\treturn nil\n}\n\n// MerkleTreeRoot return Merkle value\nfunc MerkleTreeRoot(dataArray [][]byte) []byte {\n\tresult := make(map[int32][][]byte)\n\tfor _, v := range dataArray {\n\t\thash := converter.BinToHex(crypto.DoubleHash(v))\n\t\tresult[0] = append(result[0], hash)\n\t}\n\tvar j int32\n\tfor len(result[j]) > 1 {\n\t\tfor i := 0; i < len(result[j]); i = i + 2 {\n\t\t\tif len(result[j]) <= (i + 1) {\n\t\t\t\tif _, ok := result[j+1]; !ok {\n\t\t\t\t\tresult[j+1] = [][]byte{result[j][i]}\n\t\t\t\t} else {\n\t\t\t\t\tresult[j+1] = append(result[j+1], result[j][i])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif _, ok := result[j+1]; !ok {\n\t\t\t\t\thash := crypto.DoubleHash(append(result[j][i], result[j][i+1]...))\n\t\t\t\t\thash = converter.BinToHex(hash)\n\t\t\t\t\tresult[j+1] = [][]byte{hash}\n\t\t\t\t} else {\n\t\t\t\t\thash := crypto.DoubleHash([]byte(append(result[j][i], result[j][i+1]...)))\n\t\t\t\t\thash = converter.BinToHex(hash)\n\t\t\t\t\tresult[j+1] = append(result[j+1], hash)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tj++\n\t}\n\n\tret := result[int32(len(result)-1)]\n\treturn ret[0]\n}\n\ntype BlockCandidateNode struct {\n\tID         int64\n\tReplyCount int64\n}\n"
  },
  {
    "path": "packages/types/compress.go",
    "content": "/*----------------------------------------------------------------\n- Copyright (c) IBAX. All rights reserved.\n- See LICENSE in the project root for license information.\n---------------------------------------------------------------*/\n\npackage types\n\nimport (\n\t\"bytes\"\n\t\"compress/zlib\"\n\t\"io\"\n)\n\nfunc DoZlibCompress(src []byte) []byte {\n\tvar in bytes.Buffer\n\tw := zlib.NewWriter(&in)\n\tw.Write(src)\n\tw.Close()\n\treturn in.Bytes()\n}\n\nfunc DoZlibUnCompress(compressSrc []byte) []byte {\n\tb := bytes.NewReader(compressSrc)\n\tvar out bytes.Buffer\n\tr, _ := zlib.NewReader(b)\n\tio.Copy(&out, r)\n\tr.Close()\n\treturn out.Bytes()\n}\n"
  },
  {
    "path": "packages/types/custom_tx.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage types\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/shopspring/decimal\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/vmihailenco/msgpack/v5\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n)\n\n// Transaction types.\nconst (\n\tFirstBlockTxType = iota + 1\n\tStopNetworkTxType\n\tSmartContractTxType\n\tDelayTxType\n\tUtxoTxType\n\tTransferSelfTxType\n)\n\n// FirstBlock is the header of first block transaction\ntype FirstBlock struct {\n\tKeyID                 int64\n\tTime                  int64\n\tPublicKey             []byte\n\tNodePublicKey         []byte\n\tStopNetworkCertBundle []byte\n\tTest                  int64\n\tPrivateBlockchain     uint64\n}\n\nfunc (t *FirstBlock) TxType() byte { return FirstBlockTxType }\n\ntype StopNetwork struct {\n\tKeyID           int64\n\tTime            int64\n\tStopNetworkCert []byte\n}\n\nfunc (t *StopNetwork) TxType() byte { return StopNetworkTxType }\n\n// Header is contain header data\ntype Header struct {\n\tID          int\n\tEcosystemID int64\n\tKeyID       int64\n\tTime        int64\n\tNetworkID   int64\n\tPublicKey   []byte\n}\n\ntype TransferSelf struct {\n\tValue  string\n\tSource string\n\tTarget string\n}\n\n// UTXO Transfer\ntype UTXO struct {\n\tToID    int64\n\tValue   string\n\tComment string\n}\n\n// SmartTransaction is storing smart contract data\ntype SmartTransaction struct {\n\t*Header\n\tMaxSum       string\n\tPayOver      string\n\tLang         string\n\tExpedite     string\n\tSignedBy     int64\n\tTransferSelf *TransferSelf\n\tUTXO         *UTXO\n\tParams       map[string]any\n}\n\nfunc (s *SmartTransaction) TxType() byte {\n\tif s.TransferSelf != nil {\n\t\treturn TransferSelfTxType\n\t}\n\tif s.UTXO != nil {\n\t\treturn UtxoTxType\n\t}\n\treturn SmartContractTxType\n}\n\nfunc (s *SmartTransaction) WithPrivate(privateKey []byte, internal bool) error {\n\tvar (\n\t\tpublicKey []byte\n\t\terr       error\n\t)\n\tif publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.CryptoError, \"error\": err}).Error(\"converting node private key to public\")\n\t\treturn err\n\t}\n\ts.PublicKey = publicKey\n\tif internal {\n\t\ts.SignedBy = crypto.Address(publicKey)\n\t}\n\tif s.NetworkID != conf.Config.LocalConf.NetworkID {\n\t\treturn fmt.Errorf(\"error networkid invalid\")\n\t}\n\treturn nil\n}\n\nfunc (s *SmartTransaction) Unmarshal(buffer []byte) error {\n\treturn msgpack.Unmarshal(buffer, s)\n}\n\nfunc (s *SmartTransaction) Marshal() ([]byte, error) {\n\treturn msgpack.Marshal(s)\n}\n\nfunc (t SmartTransaction) Hash() ([]byte, error) {\n\tb, err := t.Marshal()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn crypto.DoubleHash(b), nil\n}\n\nfunc (txSmart *SmartTransaction) Validate() error {\n\tif len(txSmart.Expedite) > 0 {\n\t\texpedite, err := decimal.NewFromString(txSmart.Expedite)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"wrong expedite format\")\n\t\t}\n\t\tif expedite.LessThan(decimal.Zero) {\n\t\t\treturn fmt.Errorf(\"expedite fee must be greater than 0\")\n\t\t}\n\t}\n\tif len(strings.TrimSpace(txSmart.Lang)) > 2 {\n\t\treturn fmt.Errorf(`localization size is greater than 2`)\n\t}\n\tif len(txSmart.MaxSum) > 0 && converter.StrToInt64(txSmart.MaxSum) <= 0 {\n\t\treturn fmt.Errorf(`maxsum must be greater than 0`)\n\t}\n\tif txSmart.NetworkID != conf.Config.LocalConf.NetworkID {\n\t\treturn fmt.Errorf(\"error networkid invalid\")\n\t}\n\n\tif txSmart.TransferSelf != nil {\n\t\tif ok, _ := regexp.MatchString(\"^\\\\d+$\", txSmart.TransferSelf.Value); !ok {\n\t\t\treturn errors.New(\"error TransferSelf Value must be a positive integer\")\n\t\t}\n\t\tif value, err := decimal.NewFromString(txSmart.TransferSelf.Value); err != nil || value.LessThanOrEqual(decimal.Zero) {\n\t\t\treturn errors.New(\"error TransferSelf Value must be greater than zero\")\n\t\t}\n\t\treturn nil\n\t}\n\tif txSmart.UTXO != nil {\n\t\tif converter.IDToAddress(txSmart.UTXO.ToID) == `invalid` {\n\t\t\treturn errors.New(\"error UTXO ToID must be a valid address\")\n\t\t}\n\t\tif ok, _ := regexp.MatchString(\"^\\\\d+$\", txSmart.UTXO.Value); !ok {\n\t\t\treturn errors.New(\"error UTXO Value must be a positive integer\")\n\t\t}\n\t\tif value, err := decimal.NewFromString(txSmart.UTXO.Value); err != nil || value.LessThanOrEqual(decimal.Zero) {\n\t\t\treturn errors.New(\"error UTXO Value must be greater than zero\")\n\t\t}\n\t\treturn nil\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "packages/types/file.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage types\n\n//type File *Map\n\nfunc NewFile() *Map {\n\treturn LoadMap(map[string]any{\n\t\t\"Name\":     \"\",\n\t\t\"MimeType\": \"\",\n\t\t\"Body\":     []byte{},\n\t})\n}\n\nfunc NewFileFromMap(m map[string]any) (f *Map, ok bool) {\n\tvar v any\n\tf = NewFile()\n\n\tif v, ok = m[\"Name\"].(string); !ok {\n\t\treturn\n\t}\n\tf.Set(\"Name\", v)\n\tif v, ok = m[\"MimeType\"].(string); !ok {\n\t\treturn\n\t}\n\tf.Set(\"MimeType\", v)\n\tif v, ok = m[\"Body\"].([]byte); !ok {\n\t\treturn\n\t}\n\tf.Set(\"Body\", v)\n\n\treturn\n}\n"
  },
  {
    "path": "packages/types/map.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage types\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// This is the modified version of https://github.com/jabong/florest-core/\n// https://github.com/jabong/florest-core/blob/master/src/common/collections/maps/linkedhashmap/linkedhashmap.go\n\n// Link represents a node of doubly linked list\ntype Link struct {\n\tkey   string\n\tvalue any\n\tnext  *Link\n\tprev  *Link\n}\n\n// Map holds the elements in go's native map, also maintains the head and tail link\n// to keep the elements in insertion order\ntype Map struct {\n\tm    map[string]*Link\n\thead *Link\n\ttail *Link\n}\n\nfunc newLink(key string, value any) *Link {\n\treturn &Link{key: key, value: value, next: nil, prev: nil}\n}\n\n// NewMap instantiates a linked hash map.\nfunc NewMap() *Map {\n\treturn &Map{m: make(map[string]*Link), head: nil, tail: nil}\n}\n\nfunc ConvertMap(in any) any {\n\tswitch v := in.(type) {\n\tcase map[string]any:\n\t\tout := NewMap()\n\t\tkeys := make([]string, 0, len(v))\n\t\tfor key := range v {\n\t\t\tkeys = append(keys, key)\n\t\t}\n\t\tsort.Strings(keys)\n\t\tfor _, key := range keys {\n\t\t\tswitch val := v[key].(type) {\n\t\t\tcase json.Number:\n\t\t\t\tif n, err := val.Int64(); err == nil {\n\t\t\t\t\tv[key] = n\n\t\t\t\t} else if f, err := val.Float64(); err == nil {\n\t\t\t\t\tv[key] = f\n\t\t\t\t}\n\t\t\t}\n\t\t\tout.Set(key, ConvertMap(v[key]))\n\t\t}\n\t\treturn out\n\tcase []any:\n\t\tfor i, item := range v {\n\t\t\tv[i] = ConvertMap(item)\n\t\t}\n\t}\n\treturn in\n}\n\n// LoadMap instantiates a linked hash map and initializing it from map[string]interface{}.\nfunc LoadMap(init map[string]any) (ret *Map) {\n\tret = NewMap()\n\tkeys := make([]string, 0, len(init))\n\tfor key := range init {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\tfor _, v := range keys {\n\t\tret.Set(v, ConvertMap(init[v]))\n\t}\n\treturn\n}\n\n// Put inserts an element into the map.\nfunc (m *Map) Set(key string, value any) {\n\tlink, found := m.m[key]\n\tif !found {\n\t\tlink = newLink(key, value)\n\t\tif m.tail == nil {\n\t\t\tm.head = link\n\t\t\tm.tail = link\n\t\t} else {\n\t\t\tm.tail.next = link\n\t\t\tlink.prev = m.tail\n\t\t\tm.tail = link\n\t\t}\n\t\tm.m[key] = link\n\t} else {\n\t\tlink.value = value\n\t}\n}\n\n// Get searches the element in the map by key and returns its value or nil if key doesn't exists.\n// Second return parameter is true if key was found, otherwise false.\nfunc (m *Map) Get(key string) (value any, found bool) {\n\tvar link *Link\n\tlink, found = m.m[key]\n\tif found {\n\t\tvalue = link.value\n\t} else {\n\t\tvalue = nil\n\t}\n\treturn\n}\n\n// Remove removes the element from the map by key.\nfunc (m *Map) Remove(key string) {\n\tlink, found := m.m[key]\n\tif found {\n\t\tdelete(m.m, key)\n\t\tif m.head == link && m.tail == link {\n\t\t\tm.head = nil\n\t\t\tm.tail = nil\n\t\t} else if m.tail == link {\n\t\t\tm.tail = link.prev\n\t\t\tlink.prev.next = nil\n\t\t} else if m.head == link {\n\t\t\tm.head = link.next\n\t\t\tlink.next.prev = nil\n\t\t} else {\n\t\t\tlink.prev.next = link.next\n\t\t\tlink.next.prev = link.prev\n\t\t}\n\t}\n}\n\n// IsEmpty returns true if map does not contain any elements\nfunc (m *Map) IsEmpty() bool {\n\treturn m == nil || m.Size() == 0\n}\n\n// Size returns number of elements in the map.\nfunc (m *Map) Size() int {\n\treturn len(m.m)\n}\n\n// Keys returns all keys of the map (insertion order).\nfunc (m *Map) Keys() []string {\n\tkeys := make([]string, m.Size())\n\tcount := 0\n\tfor current := m.head; current != nil; current = current.next {\n\t\tkeys[count] = current.key\n\t\tcount++\n\t}\n\treturn keys\n}\n\n// Values returns all values of the map (insertion order).\nfunc (m *Map) Values() []any {\n\tvalues := make([]any, m.Size())\n\tcount := 0\n\tfor current := m.head; current != nil; current = current.next {\n\t\tvalues[count] = current.value\n\t\tcount++\n\t}\n\treturn values\n}\n\n// Clear removes all elements from the map.\nfunc (m *Map) Clear() {\n\tm.m = make(map[string]*Link)\n\tm.head = nil\n\tm.tail = nil\n}\n\n// String returns a string representation of container\nfunc (m *Map) String() string {\n\tstr := \"map[\"\n\tfor current := m.head; current != nil; current = current.next {\n\t\tstr += fmt.Sprintf(\"%v:%v \", current.key, current.value)\n\t}\n\treturn strings.TrimRight(str, \" \") + \"]\"\n}\n\nfunc (m *Map) MarshalJSON() ([]byte, error) {\n\ts := \"{\"\n\tfor current := m.head; current != nil; current = current.next {\n\t\tk := current.key\n\t\tescaped := strings.Replace(k, `\"`, `\\\"`, -1)\n\t\ts = s + `\"` + escaped + `\":`\n\t\tv := current.value\n\t\tvBytes, err := json.Marshal(v)\n\t\tif err != nil {\n\t\t\treturn []byte{}, err\n\t\t}\n\t\ts = s + string(vBytes) + \",\"\n\t}\n\tif len(s) > 1 {\n\t\ts = s[0 : len(s)-1]\n\t}\n\ts = s + \"}\"\n\treturn []byte(s), nil\n}\n"
  },
  {
    "path": "packages/types/mode_interfaces.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage types\n\nimport (\n\t\"context\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n// ClientTxPreprocessor procees tx from client\ntype ClientTxPreprocessor interface {\n\t//ProcessClientTranstaction([]byte, int64, *log.Entry) (string, error)\n\tProcessClientTxBatches([][]byte, int64, *log.Entry) ([]string, error)\n}\n\n// SmartContractRunner run serialized contract\ntype SmartContractRunner interface {\n\tRunContract(data, hash []byte, keyID, tnow int64, le *log.Entry) error\n}\n\ntype DaemonFactory interface {\n\tGetDaemonsList() []string\n\tLoad(context.Context) error\n}\n"
  },
  {
    "path": "packages/types/notifications.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage types\n\ntype Notifications interface {\n\tAddAccounts(ecosystem int64, accounts ...string)\n\tAddRoles(ecosystem int64, roles ...int64)\n\tSize() int\n\tSend()\n}\n"
  },
  {
    "path": "packages/types/play.pb.go",
    "content": "// Code generated by protoc-gen-gogo. DO NOT EDIT.\n// source: play.proto\n\npackage types\n\nimport (\n\tfmt \"fmt\"\n\tpbgo \"github.com/IBAX-io/go-ibax/packages/pbgo\"\n\tproto \"github.com/gogo/protobuf/proto\"\n\tio \"io\"\n\tmath \"math\"\n\tmath_bits \"math/bits\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package\n\n//AfterTxs defined block batch process tx for sql DML\ntype AfterTxs struct {\n\tTxs []*AfterTx `protobuf:\"bytes,1,rep,name=txs,proto3\" json:\"txs,omitempty\"`\n\t//TxBinLogSql defined contract exec sql for tx DML\n\t//  repeated bytes tx_bin_log_sql = 2;\n\tRts []*RollbackTx `protobuf:\"bytes,3,rep,name=rts,proto3\" json:\"rts,omitempty\"`\n}\n\nfunc (m *AfterTxs) Reset()         { *m = AfterTxs{} }\nfunc (m *AfterTxs) String() string { return proto.CompactTextString(m) }\nfunc (*AfterTxs) ProtoMessage()    {}\nfunc (*AfterTxs) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_e999501ad2a3bf5d, []int{0}\n}\nfunc (m *AfterTxs) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *AfterTxs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_AfterTxs.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *AfterTxs) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_AfterTxs.Merge(m, src)\n}\nfunc (m *AfterTxs) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *AfterTxs) XXX_DiscardUnknown() {\n\txxx_messageInfo_AfterTxs.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_AfterTxs proto.InternalMessageInfo\n\nfunc (m *AfterTxs) GetTxs() []*AfterTx {\n\tif m != nil {\n\t\treturn m.Txs\n\t}\n\treturn nil\n}\n\nfunc (m *AfterTxs) GetRts() []*RollbackTx {\n\tif m != nil {\n\t\treturn m.Rts\n\t}\n\treturn nil\n}\n\ntype AfterTx struct {\n\tUsedTx      []byte          `protobuf:\"bytes,1,opt,name=used_tx,json=usedTx,proto3\" json:\"used_tx,omitempty\"`\n\tLts         *LogTransaction `protobuf:\"bytes,2,opt,name=lts,proto3\" json:\"lts,omitempty\"`\n\tUpdTxStatus *pbgo.TxResult  `protobuf:\"bytes,3,opt,name=upd_tx_status,json=updTxStatus,proto3\" json:\"upd_tx_status,omitempty\"`\n}\n\nfunc (m *AfterTx) Reset()         { *m = AfterTx{} }\nfunc (m *AfterTx) String() string { return proto.CompactTextString(m) }\nfunc (*AfterTx) ProtoMessage()    {}\nfunc (*AfterTx) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_e999501ad2a3bf5d, []int{1}\n}\nfunc (m *AfterTx) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *AfterTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_AfterTx.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *AfterTx) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_AfterTx.Merge(m, src)\n}\nfunc (m *AfterTx) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *AfterTx) XXX_DiscardUnknown() {\n\txxx_messageInfo_AfterTx.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_AfterTx proto.InternalMessageInfo\n\nfunc (m *AfterTx) GetUsedTx() []byte {\n\tif m != nil {\n\t\treturn m.UsedTx\n\t}\n\treturn nil\n}\n\nfunc (m *AfterTx) GetLts() *LogTransaction {\n\tif m != nil {\n\t\treturn m.Lts\n\t}\n\treturn nil\n}\n\nfunc (m *AfterTx) GetUpdTxStatus() *pbgo.TxResult {\n\tif m != nil {\n\t\treturn m.UpdTxStatus\n\t}\n\treturn nil\n}\n\ntype RollbackTx struct {\n\tId        int64  `protobuf:\"varint,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tBlockId   int64  `protobuf:\"varint,2,opt,name=block_id,json=blockId,proto3\" json:\"block_id,omitempty\"`\n\tTxHash    []byte `protobuf:\"bytes,3,opt,name=tx_hash,json=txHash,proto3\" json:\"tx_hash,omitempty\"`\n\tNameTable string `protobuf:\"bytes,4,opt,name=name_table,json=nameTable,proto3\" json:\"name_table,omitempty\"`\n\tTableId   string `protobuf:\"bytes,5,opt,name=table_id,json=tableId,proto3\" json:\"table_id,omitempty\"`\n\tData      string `protobuf:\"bytes,6,opt,name=data,proto3\" json:\"data,omitempty\"`\n\tDataHash  []byte `protobuf:\"bytes,7,opt,name=data_hash,json=dataHash,proto3\" json:\"data_hash,omitempty\"`\n}\n\nfunc (m *RollbackTx) Reset()         { *m = RollbackTx{} }\nfunc (m *RollbackTx) String() string { return proto.CompactTextString(m) }\nfunc (*RollbackTx) ProtoMessage()    {}\nfunc (*RollbackTx) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_e999501ad2a3bf5d, []int{2}\n}\nfunc (m *RollbackTx) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *RollbackTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_RollbackTx.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *RollbackTx) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_RollbackTx.Merge(m, src)\n}\nfunc (m *RollbackTx) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *RollbackTx) XXX_DiscardUnknown() {\n\txxx_messageInfo_RollbackTx.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_RollbackTx proto.InternalMessageInfo\n\nfunc (m *RollbackTx) GetId() int64 {\n\tif m != nil {\n\t\treturn m.Id\n\t}\n\treturn 0\n}\n\nfunc (m *RollbackTx) GetBlockId() int64 {\n\tif m != nil {\n\t\treturn m.BlockId\n\t}\n\treturn 0\n}\n\nfunc (m *RollbackTx) GetTxHash() []byte {\n\tif m != nil {\n\t\treturn m.TxHash\n\t}\n\treturn nil\n}\n\nfunc (m *RollbackTx) GetNameTable() string {\n\tif m != nil {\n\t\treturn m.NameTable\n\t}\n\treturn \"\"\n}\n\nfunc (m *RollbackTx) GetTableId() string {\n\tif m != nil {\n\t\treturn m.TableId\n\t}\n\treturn \"\"\n}\n\nfunc (m *RollbackTx) GetData() string {\n\tif m != nil {\n\t\treturn m.Data\n\t}\n\treturn \"\"\n}\n\nfunc (m *RollbackTx) GetDataHash() []byte {\n\tif m != nil {\n\t\treturn m.DataHash\n\t}\n\treturn nil\n}\n\ntype LogTransaction struct {\n\tHash  []byte `protobuf:\"bytes,1,opt,name=hash,proto3\" json:\"hash,omitempty\"`\n\tBlock int64  `protobuf:\"varint,2,opt,name=block,proto3\" json:\"block,omitempty\"`\n\t//  bytes tx_data = 3;\n\tTimestamp    int64                   `protobuf:\"varint,4,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\tAddress      int64                   `protobuf:\"varint,5,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tEcosystemId  int64                   `protobuf:\"varint,6,opt,name=ecosystem_id,json=ecosystemId,proto3\" json:\"ecosystem_id,omitempty\"`\n\tContractName string                  `protobuf:\"bytes,7,opt,name=contract_name,json=contractName,proto3\" json:\"contract_name,omitempty\"`\n\tInvokeStatus pbgo.TxInvokeStatusCode `protobuf:\"varint,8,opt,name=invoke_status,json=invokeStatus,proto3,enum=pbgo.TxInvokeStatusCode\" json:\"invoke_status,omitempty\"`\n}\n\nfunc (m *LogTransaction) Reset()         { *m = LogTransaction{} }\nfunc (m *LogTransaction) String() string { return proto.CompactTextString(m) }\nfunc (*LogTransaction) ProtoMessage()    {}\nfunc (*LogTransaction) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_e999501ad2a3bf5d, []int{3}\n}\nfunc (m *LogTransaction) XXX_Unmarshal(b []byte) error {\n\treturn m.Unmarshal(b)\n}\nfunc (m *LogTransaction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\tif deterministic {\n\t\treturn xxx_messageInfo_LogTransaction.Marshal(b, m, deterministic)\n\t} else {\n\t\tb = b[:cap(b)]\n\t\tn, err := m.MarshalToSizedBuffer(b)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn b[:n], nil\n\t}\n}\nfunc (m *LogTransaction) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_LogTransaction.Merge(m, src)\n}\nfunc (m *LogTransaction) XXX_Size() int {\n\treturn m.Size()\n}\nfunc (m *LogTransaction) XXX_DiscardUnknown() {\n\txxx_messageInfo_LogTransaction.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_LogTransaction proto.InternalMessageInfo\n\nfunc (m *LogTransaction) GetHash() []byte {\n\tif m != nil {\n\t\treturn m.Hash\n\t}\n\treturn nil\n}\n\nfunc (m *LogTransaction) GetBlock() int64 {\n\tif m != nil {\n\t\treturn m.Block\n\t}\n\treturn 0\n}\n\nfunc (m *LogTransaction) GetTimestamp() int64 {\n\tif m != nil {\n\t\treturn m.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (m *LogTransaction) GetAddress() int64 {\n\tif m != nil {\n\t\treturn m.Address\n\t}\n\treturn 0\n}\n\nfunc (m *LogTransaction) GetEcosystemId() int64 {\n\tif m != nil {\n\t\treturn m.EcosystemId\n\t}\n\treturn 0\n}\n\nfunc (m *LogTransaction) GetContractName() string {\n\tif m != nil {\n\t\treturn m.ContractName\n\t}\n\treturn \"\"\n}\n\nfunc (m *LogTransaction) GetInvokeStatus() pbgo.TxInvokeStatusCode {\n\tif m != nil {\n\t\treturn m.InvokeStatus\n\t}\n\treturn pbgo.TxInvokeStatusCode_SUCCESS\n}\n\nfunc init() {\n\tproto.RegisterType((*AfterTxs)(nil), \"types.AfterTxs\")\n\tproto.RegisterType((*AfterTx)(nil), \"types.AfterTx\")\n\tproto.RegisterType((*RollbackTx)(nil), \"types.RollbackTx\")\n\tproto.RegisterType((*LogTransaction)(nil), \"types.LogTransaction\")\n}\n\nfunc init() { proto.RegisterFile(\"play.proto\", fileDescriptor_e999501ad2a3bf5d) }\n\nvar fileDescriptor_e999501ad2a3bf5d = []byte{\n\t// 515 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x52, 0x3d, 0x8f, 0xd3, 0x40,\n\t0x10, 0xbd, 0x3d, 0xdf, 0xc5, 0xc9, 0x24, 0x17, 0x89, 0x15, 0x08, 0xf3, 0x65, 0x99, 0x5c, 0x41,\n\t0x28, 0x2e, 0x91, 0x42, 0x4d, 0x71, 0x77, 0x0d, 0x91, 0x10, 0x12, 0x8b, 0x0b, 0x44, 0x63, 0xad,\n\t0xbd, 0x4b, 0x62, 0xc5, 0xce, 0x5a, 0xde, 0x31, 0xf2, 0x55, 0xfc, 0x05, 0xfe, 0x0f, 0x7f, 0x80,\n\t0xf2, 0x4a, 0x4a, 0x94, 0xfc, 0x0a, 0x3a, 0xb4, 0x93, 0x84, 0x83, 0xca, 0x3b, 0xef, 0x3d, 0xcf,\n\t0x7b, 0xb3, 0xb3, 0x00, 0x55, 0x21, 0x6f, 0x26, 0x55, 0x6d, 0xd0, 0xf0, 0x53, 0xbc, 0xa9, 0xb4,\n\t0x7d, 0xdc, 0xc5, 0x76, 0x07, 0x8c, 0xde, 0x43, 0xf7, 0xf2, 0x33, 0xea, 0x3a, 0x6e, 0x2d, 0x8f,\n\t0xc0, 0xc3, 0xd6, 0x06, 0x2c, 0xf2, 0xc6, 0xfd, 0xd9, 0x70, 0x42, 0xd2, 0xc9, 0x9e, 0x15, 0x8e,\n\t0xe2, 0xe7, 0xe0, 0xd5, 0x68, 0x03, 0x8f, 0x14, 0xf7, 0xf6, 0x0a, 0x61, 0x8a, 0x22, 0x95, 0xd9,\n\t0xca, 0x89, 0x6a, 0xb4, 0xa3, 0xaf, 0xe0, 0xef, 0x7f, 0xe2, 0x0f, 0xc1, 0x6f, 0xac, 0x56, 0x09,\n\t0xb6, 0x01, 0x8b, 0xd8, 0x78, 0x20, 0x3a, 0xae, 0x8c, 0x5b, 0xfe, 0x02, 0xbc, 0x02, 0x6d, 0x70,\n\t0x1c, 0xb1, 0x71, 0x7f, 0xf6, 0x60, 0xdf, 0xe8, 0xad, 0x59, 0xc4, 0xb5, 0x5c, 0x5b, 0x99, 0x61,\n\t0x6e, 0xd6, 0xc2, 0x29, 0xf8, 0x0c, 0xce, 0x9a, 0xca, 0x35, 0x48, 0x2c, 0x4a, 0x6c, 0x9c, 0x37,\n\t0xa3, 0x74, 0x55, 0xba, 0x30, 0x93, 0xb8, 0x15, 0xda, 0x36, 0x05, 0x8a, 0x7e, 0x53, 0xa9, 0xb8,\n\t0xfd, 0x40, 0x92, 0xd1, 0x77, 0x06, 0x70, 0x17, 0x8a, 0x0f, 0xe1, 0x38, 0x57, 0xe4, 0xef, 0x89,\n\t0xe3, 0x5c, 0xf1, 0x47, 0xd0, 0x4d, 0x0b, 0x93, 0xad, 0x92, 0x5c, 0x51, 0x00, 0x4f, 0xf8, 0x54,\n\t0xcf, 0x95, 0xcb, 0x8b, 0x6d, 0xb2, 0x94, 0x76, 0x49, 0x3e, 0x03, 0xd1, 0xc1, 0xf6, 0x8d, 0xb4,\n\t0x4b, 0xfe, 0x0c, 0x60, 0x2d, 0x4b, 0x9d, 0xa0, 0x4c, 0x0b, 0x1d, 0x9c, 0x44, 0x6c, 0xdc, 0x13,\n\t0x3d, 0x87, 0xc4, 0x0e, 0x70, 0x2d, 0x89, 0x71, 0x2d, 0x4f, 0x89, 0xf4, 0xa9, 0x9e, 0x2b, 0xce,\n\t0xe1, 0x44, 0x49, 0x94, 0x41, 0x87, 0x60, 0x3a, 0xf3, 0x27, 0xd0, 0x73, 0xdf, 0x9d, 0x91, 0x4f,\n\t0x46, 0x5d, 0x07, 0x38, 0xab, 0xd1, 0x6f, 0x06, 0xc3, 0xff, 0x6f, 0xc2, 0xf5, 0x20, 0xe9, 0xee,\n\t0x0e, 0xe9, 0xcc, 0xef, 0xc3, 0x29, 0xa5, 0xde, 0x8f, 0xb0, 0x2b, 0xf8, 0x53, 0xe8, 0x61, 0x5e,\n\t0x6a, 0x8b, 0xb2, 0xac, 0x28, 0xa6, 0x27, 0xee, 0x00, 0x1e, 0x80, 0x2f, 0x95, 0xaa, 0xb5, 0xb5,\n\t0x94, 0xd2, 0x13, 0x87, 0x92, 0x3f, 0x87, 0x81, 0xce, 0x8c, 0xbd, 0xb1, 0xa8, 0x4b, 0x37, 0x44,\n\t0x87, 0xe8, 0xfe, 0x5f, 0x6c, 0xae, 0xf8, 0x39, 0x9c, 0x65, 0x66, 0x8d, 0xb5, 0xcc, 0x30, 0x71,\n\t0x93, 0x53, 0xf0, 0x9e, 0x18, 0x1c, 0xc0, 0x77, 0xb2, 0xd4, 0xfc, 0x35, 0x9c, 0xe5, 0xeb, 0x2f,\n\t0x66, 0xa5, 0x0f, 0xeb, 0xea, 0x46, 0x6c, 0x3c, 0x9c, 0x05, 0x87, 0x75, 0xcd, 0x89, 0xdc, 0xed,\n\t0xe9, 0xda, 0x28, 0x2d, 0x06, 0xf9, 0x3f, 0xc8, 0xd5, 0xf5, 0x8f, 0x4d, 0xc8, 0x6e, 0x37, 0x21,\n\t0xfb, 0xb5, 0x09, 0xd9, 0xb7, 0x6d, 0x78, 0x74, 0xbb, 0x0d, 0x8f, 0x7e, 0x6e, 0xc3, 0xa3, 0x4f,\n\t0x2f, 0x17, 0x39, 0x2e, 0x9b, 0x74, 0x92, 0x99, 0x72, 0x3a, 0xbf, 0xba, 0xfc, 0x78, 0x91, 0x9b,\n\t0xe9, 0xc2, 0x5c, 0xe4, 0xa9, 0x6c, 0xa7, 0x95, 0xcc, 0x56, 0x72, 0xa1, 0xed, 0x94, 0x9e, 0x51,\n\t0xda, 0xa1, 0x97, 0xfd, 0xea, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9b, 0x9f, 0x46, 0xe8, 0xf8,\n\t0x02, 0x00, 0x00,\n}\n\nfunc (m *AfterTxs) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AfterTxs) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *AfterTxs) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif len(m.Rts) > 0 {\n\t\tfor iNdEx := len(m.Rts) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\t{\n\t\t\t\tsize, err := m.Rts[iNdEx].MarshalToSizedBuffer(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = encodeVarintPlay(dAtA, i, uint64(size))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.Txs) > 0 {\n\t\tfor iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\t{\n\t\t\t\tsize, err := m.Txs[iNdEx].MarshalToSizedBuffer(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = encodeVarintPlay(dAtA, i, uint64(size))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AfterTx) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AfterTx) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *AfterTx) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.UpdTxStatus != nil {\n\t\t{\n\t\t\tsize, err := m.UpdTxStatus.MarshalToSizedBuffer(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = encodeVarintPlay(dAtA, i, uint64(size))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Lts != nil {\n\t\t{\n\t\t\tsize, err := m.Lts.MarshalToSizedBuffer(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = encodeVarintPlay(dAtA, i, uint64(size))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.UsedTx) > 0 {\n\t\ti -= len(m.UsedTx)\n\t\tcopy(dAtA[i:], m.UsedTx)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.UsedTx)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RollbackTx) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RollbackTx) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *RollbackTx) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif len(m.DataHash) > 0 {\n\t\ti -= len(m.DataHash)\n\t\tcopy(dAtA[i:], m.DataHash)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.DataHash)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.Data) > 0 {\n\t\ti -= len(m.Data)\n\t\tcopy(dAtA[i:], m.Data)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.Data)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.TableId) > 0 {\n\t\ti -= len(m.TableId)\n\t\tcopy(dAtA[i:], m.TableId)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.TableId)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.NameTable) > 0 {\n\t\ti -= len(m.NameTable)\n\t\tcopy(dAtA[i:], m.NameTable)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.NameTable)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.TxHash) > 0 {\n\t\ti -= len(m.TxHash)\n\t\tcopy(dAtA[i:], m.TxHash)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.TxHash)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.BlockId != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.BlockId))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Id != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.Id))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LogTransaction) Marshal() (dAtA []byte, err error) {\n\tsize := m.Size()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBuffer(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LogTransaction) MarshalTo(dAtA []byte) (int, error) {\n\tsize := m.Size()\n\treturn m.MarshalToSizedBuffer(dAtA[:size])\n}\n\nfunc (m *LogTransaction) MarshalToSizedBuffer(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.InvokeStatus != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.InvokeStatus))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif len(m.ContractName) > 0 {\n\t\ti -= len(m.ContractName)\n\t\tcopy(dAtA[i:], m.ContractName)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.ContractName)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.EcosystemId != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.EcosystemId))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Address != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.Address))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Timestamp != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.Timestamp))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Block != 0 {\n\t\ti = encodeVarintPlay(dAtA, i, uint64(m.Block))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Hash) > 0 {\n\t\ti -= len(m.Hash)\n\t\tcopy(dAtA[i:], m.Hash)\n\t\ti = encodeVarintPlay(dAtA, i, uint64(len(m.Hash)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc encodeVarintPlay(dAtA []byte, offset int, v uint64) int {\n\toffset -= sovPlay(v)\n\tbase := offset\n\tfor v >= 1<<7 {\n\t\tdAtA[offset] = uint8(v&0x7f | 0x80)\n\t\tv >>= 7\n\t\toffset++\n\t}\n\tdAtA[offset] = uint8(v)\n\treturn base\n}\nfunc (m *AfterTxs) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Txs) > 0 {\n\t\tfor _, e := range m.Txs {\n\t\t\tl = e.Size()\n\t\t\tn += 1 + l + sovPlay(uint64(l))\n\t\t}\n\t}\n\tif len(m.Rts) > 0 {\n\t\tfor _, e := range m.Rts {\n\t\t\tl = e.Size()\n\t\t\tn += 1 + l + sovPlay(uint64(l))\n\t\t}\n\t}\n\treturn n\n}\n\nfunc (m *AfterTx) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.UsedTx)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tif m.Lts != nil {\n\t\tl = m.Lts.Size()\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tif m.UpdTxStatus != nil {\n\t\tl = m.UpdTxStatus.Size()\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\treturn n\n}\n\nfunc (m *RollbackTx) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Id != 0 {\n\t\tn += 1 + sovPlay(uint64(m.Id))\n\t}\n\tif m.BlockId != 0 {\n\t\tn += 1 + sovPlay(uint64(m.BlockId))\n\t}\n\tl = len(m.TxHash)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tl = len(m.NameTable)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tl = len(m.TableId)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tl = len(m.Data)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tl = len(m.DataHash)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\treturn n\n}\n\nfunc (m *LogTransaction) Size() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hash)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tif m.Block != 0 {\n\t\tn += 1 + sovPlay(uint64(m.Block))\n\t}\n\tif m.Timestamp != 0 {\n\t\tn += 1 + sovPlay(uint64(m.Timestamp))\n\t}\n\tif m.Address != 0 {\n\t\tn += 1 + sovPlay(uint64(m.Address))\n\t}\n\tif m.EcosystemId != 0 {\n\t\tn += 1 + sovPlay(uint64(m.EcosystemId))\n\t}\n\tl = len(m.ContractName)\n\tif l > 0 {\n\t\tn += 1 + l + sovPlay(uint64(l))\n\t}\n\tif m.InvokeStatus != 0 {\n\t\tn += 1 + sovPlay(uint64(m.InvokeStatus))\n\t}\n\treturn n\n}\n\nfunc sovPlay(x uint64) (n int) {\n\treturn (math_bits.Len64(x|1) + 6) / 7\n}\nfunc sozPlay(x uint64) (n int) {\n\treturn sovPlay(uint64((x << 1) ^ uint64((int64(x) >> 63))))\n}\nfunc (m *AfterTxs) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AfterTxs: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AfterTxs: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Txs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Txs = append(m.Txs, &AfterTx{})\n\t\t\tif err := m.Txs[len(m.Txs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rts\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Rts = append(m.Rts, &RollbackTx{})\n\t\t\tif err := m.Rts[len(m.Rts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipPlay(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AfterTx) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AfterTx: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AfterTx: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UsedTx\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UsedTx = append(m.UsedTx[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.UsedTx == nil {\n\t\t\t\tm.UsedTx = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Lts\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Lts == nil {\n\t\t\t\tm.Lts = &LogTransaction{}\n\t\t\t}\n\t\t\tif err := m.Lts.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UpdTxStatus\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.UpdTxStatus == nil {\n\t\t\t\tm.UpdTxStatus = &pbgo.TxResult{}\n\t\t\t}\n\t\t\tif err := m.UpdTxStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipPlay(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RollbackTx) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RollbackTx: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RollbackTx: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tm.Id = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Id |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockId\", wireType)\n\t\t\t}\n\t\t\tm.BlockId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BlockId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxHash\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TxHash = append(m.TxHash[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.TxHash == nil {\n\t\t\t\tm.TxHash = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NameTable\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NameTable = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TableId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TableId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Data\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Data = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DataHash\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DataHash = append(m.DataHash[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.DataHash == nil {\n\t\t\t\tm.DataHash = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipPlay(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LogTransaction) Unmarshal(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LogTransaction: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LogTransaction: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hash\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Hash == nil {\n\t\t\t\tm.Hash = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Block\", wireType)\n\t\t\t}\n\t\t\tm.Block = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Block |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timestamp\", wireType)\n\t\t\t}\n\t\t\tm.Timestamp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timestamp |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tm.Address = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Address |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EcosystemId\", wireType)\n\t\t\t}\n\t\t\tm.EcosystemId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.EcosystemId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ContractName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ContractName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InvokeStatus\", wireType)\n\t\t\t}\n\t\t\tm.InvokeStatus = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.InvokeStatus |= pbgo.TxInvokeStatusCode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := skipPlay(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc skipPlay(dAtA []byte) (n int, err error) {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tdepth := 0\n\tfor iNdEx < l {\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn 0, ErrIntOverflowPlay\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= (uint64(b) & 0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\twireType := int(wire & 0x7)\n\t\tswitch wireType {\n\t\tcase 0:\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tiNdEx++\n\t\t\t\tif dAtA[iNdEx-1] < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 1:\n\t\t\tiNdEx += 8\n\t\tcase 2:\n\t\t\tvar length int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn 0, ErrIntOverflowPlay\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tlength |= (int(b) & 0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif length < 0 {\n\t\t\t\treturn 0, ErrInvalidLengthPlay\n\t\t\t}\n\t\t\tiNdEx += length\n\t\tcase 3:\n\t\t\tdepth++\n\t\tcase 4:\n\t\t\tif depth == 0 {\n\t\t\t\treturn 0, ErrUnexpectedEndOfGroupPlay\n\t\t\t}\n\t\t\tdepth--\n\t\tcase 5:\n\t\t\tiNdEx += 4\n\t\tdefault:\n\t\t\treturn 0, fmt.Errorf(\"proto: illegal wireType %d\", wireType)\n\t\t}\n\t\tif iNdEx < 0 {\n\t\t\treturn 0, ErrInvalidLengthPlay\n\t\t}\n\t\tif depth == 0 {\n\t\t\treturn iNdEx, nil\n\t\t}\n\t}\n\treturn 0, io.ErrUnexpectedEOF\n}\n\nvar (\n\tErrInvalidLengthPlay        = fmt.Errorf(\"proto: negative length found during unmarshaling\")\n\tErrIntOverflowPlay          = fmt.Errorf(\"proto: integer overflow\")\n\tErrUnexpectedEndOfGroupPlay = fmt.Errorf(\"proto: unexpected end of group\")\n)\n"
  },
  {
    "path": "packages/utils/ban_error.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport (\n\t\"github.com/pkg/errors\"\n)\n\ntype BanError struct {\n\terr error\n}\n\nfunc (b *BanError) Error() string {\n\treturn b.err.Error()\n}\n\nfunc WithBan(err error) error {\n\treturn &BanError{\n\t\terr: err,\n\t}\n}\n\nfunc IsBanError(err error) bool {\n\terr = errors.Cause(err)\n\tif _, ok := err.(*BanError); ok {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "packages/utils/ban_error_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport (\n\t\"testing\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBanError(t *testing.T) {\n\tcases := map[error]bool{\n\t\terrors.New(\"case 1\"):                                  false,\n\t\tWithBan(errors.New(\"case 2\")):                         true,\n\t\terrors.Wrap(errors.New(\"case 3\"), \"message\"):          false,\n\t\terrors.Wrap(WithBan(errors.New(\"case 4\")), \"message\"): true,\n\t}\n\n\tfor err, ok := range cases {\n\t\tassert.Equal(t, ok, IsBanError(err), err.Error())\n\t}\n}\n"
  },
  {
    "path": "packages/utils/clock.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport \"time\"\n\n// Clock represents interface of clock\ntype Clock interface {\n\tNow() time.Time\n}\n\n// ClockWrapper represents wrapper of clock\ntype ClockWrapper struct {\n}\n\n// Now returns current time\nfunc (cw *ClockWrapper) Now() time.Time { return time.Now() }\n"
  },
  {
    "path": "packages/utils/clock_mock.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport (\n\t\"time\"\n\n\t\"github.com/stretchr/testify/mock\"\n)\n\n// MockClock is an autogenerated mock type for the Clock type\ntype MockClock struct {\n\tmock.Mock\n}\n\n// Now provides a mock function with given fields:\nfunc (_m *MockClock) Now() time.Time {\n\tret := _m.Called()\n\n\tvar r0 time.Time\n\tif rf, ok := ret.Get(0).(func() time.Time); ok {\n\t\tr0 = rf()\n\t} else {\n\t\tr0 = ret.Get(0).(time.Time)\n\t}\n\n\treturn r0\n}\n"
  },
  {
    "path": "packages/utils/metric/collector.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\npackage metric\n\nimport (\n\t\"github.com/IBAX-io/go-ibax/packages/types\"\n)\n\n// CollectorFunc represents function for collects values of metrics\ntype CollectorFunc func(int64) ([]*Value, error)\n\n// Value represents value of metrics\ntype Value struct {\n\tTime   int64\n\tMetric string\n\tKey    string\n\tValue  int64\n}\n\n// ToMap returns values as map\nfunc (v *Value) ToMap() *types.Map {\n\treturn types.LoadMap(map[string]any{\n\t\t\"time\":   v.Time,\n\t\t\"metric\": v.Metric,\n\t\t\"key\":    v.Key,\n\t\t\"value\":  v.Value,\n\t})\n}\n\n// Collector represents struct that works with the collection of metrics\ntype Collector struct {\n\tfuncs []CollectorFunc\n}\n\n// Values returns values of all metrics\nfunc (c *Collector) Values(timeBlock int64) []any {\n\tvalues := make([]any, 0)\n\tfor _, fn := range c.funcs {\n\t\tresult, err := fn(timeBlock)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, v := range result {\n\t\t\tvalues = append(values, v.ToMap())\n\t\t}\n\t}\n\treturn values\n}\n\n// NewCollector creates new collector\nfunc NewCollector(funcs ...CollectorFunc) *Collector {\n\tc := &Collector{}\n\tc.funcs = make([]CollectorFunc, 0, len(funcs))\n\tc.funcs = append(c.funcs, funcs...)\n\treturn c\n}\n"
  },
  {
    "path": "packages/utils/metric/collector_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage metric\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc MockValue(v int64) *Value {\n\treturn &Value{Time: 1, Metric: \"test_metric\", Key: \"ecosystem_1\", Value: v}\n}\n\nfunc MockCollectorFunc(v int64, err error) CollectorFunc {\n\treturn func() ([]*Value, error) {\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn []*Value{MockValue(v)}, nil\n\t}\n}\n\nfunc TestValue(t *testing.T) {\n\tvalue := MockValue(100)\n\tresult := map[string]any{\"time\": int64(1), \"metric\": \"test_metric\", \"key\": \"ecosystem_1\", \"value\": int64(100)}\n\tassert.Equal(t, result, value.ToMap())\n}\n\nfunc TestCollector(t *testing.T) {\n\tc := NewCollector(\n\t\tMockCollectorFunc(100, nil),\n\t\tMockCollectorFunc(0, errors.New(\"Test\")),\n\t\tMockCollectorFunc(200, nil),\n\t)\n\n\tresult := []any{\n\t\tmap[string]any{\"time\": int64(1), \"metric\": \"test_metric\", \"key\": \"ecosystem_1\", \"value\": int64(100)},\n\t\tmap[string]any{\"time\": int64(1), \"metric\": \"test_metric\", \"key\": \"ecosystem_1\", \"value\": int64(200)},\n\t}\n\tassert.Equal(t, result, c.Values())\n}\n"
  },
  {
    "path": "packages/utils/metric/metrics.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage metric\n\nimport (\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/storage/sqldb\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst (\n\tmetricEcosystemPages   = \"ecosystem_pages\"\n\tmetricEcosystemMembers = \"ecosystem_members\"\n\tmetricEcosystemTx      = \"ecosystem_tx\"\n)\n\n// CollectMetricDataForEcosystemTables returns metrics for some tables of ecosystems\nfunc CollectMetricDataForEcosystemTables(timeBlock int64) (metricValues []*Value, err error) {\n\tstateIDs, _, err := sqldb.GetAllSystemStatesIDs()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"get all system states ids\")\n\t\treturn nil, err\n\t}\n\n\tnow := time.Unix(timeBlock, 0)\n\tunixDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Unix()\n\n\tfor _, stateID := range stateIDs {\n\t\tvar pagesCount, membersCount int64\n\n\t\ttablePrefix := strconv.FormatInt(stateID, 10)\n\n\t\tp := &sqldb.Page{}\n\t\tp.SetTablePrefix(tablePrefix)\n\t\tif pagesCount, err = p.Count(); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"get count of pages\")\n\t\t\treturn nil, err\n\t\t}\n\t\tmetricValues = append(metricValues, &Value{\n\t\t\tTime:   unixDate,\n\t\t\tMetric: metricEcosystemPages,\n\t\t\tKey:    tablePrefix,\n\t\t\tValue:  pagesCount,\n\t\t})\n\n\t\tm := &sqldb.Member{}\n\t\tm.SetTablePrefix(tablePrefix)\n\t\tif membersCount, err = m.Count(); err != nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"get count of members\")\n\t\t\treturn nil, err\n\t\t}\n\t\tmetricValues = append(metricValues, &Value{\n\t\t\tTime:   unixDate,\n\t\t\tMetric: metricEcosystemMembers,\n\t\t\tKey:    tablePrefix,\n\t\t\tValue:  membersCount,\n\t\t})\n\t}\n\n\treturn metricValues, nil\n}\n\n// CollectMetricDataForEcosystemTx returns metrics for transactions of ecosystems\nfunc CollectMetricDataForEcosystemTx(timeBlock int64) (metricValues []*Value, err error) {\n\tecosystemTx, err := sqldb.GetEcosystemTxPerDay(timeBlock)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.DBError}).Error(\"get ecosystem transactions by period\")\n\t\treturn nil, err\n\t}\n\tfor _, item := range ecosystemTx {\n\t\tif len(item.Ecosystem) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tmetricValues = append(metricValues, &Value{\n\t\t\tTime:   item.UnixTime,\n\t\t\tMetric: metricEcosystemTx,\n\t\t\tKey:    item.Ecosystem,\n\t\t\tValue:  item.Count,\n\t\t})\n\t}\n\n\treturn metricValues, nil\n}\n"
  },
  {
    "path": "packages/utils/ntp.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport (\n\t\"net\"\n\t\"sort\"\n\n\t\"time\"\n)\n\nconst (\n\tntpPool        = \"pool.ntp.org\"  // ntpPool is the NTP server to query for the current time\n\tntpChecks      = 3               // Number of measurements to do against the NTP server\n\tdriftThreshold = 1 * time.Second // Allowed clock drift before warning user\n)\n\n// durationSlice attaches the methods of sort.Interface to []time.Duration,\n// sorting in increasing order.\ntype durationSlice []time.Duration\n\nfunc (s durationSlice) Len() int           { return len(s) }\nfunc (s durationSlice) Less(i, j int) bool { return s[i] < s[j] }\nfunc (s durationSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }\n\n// CheckClockDrift queries an NTP server for clock drifts and warns the user if\n// one large enough is detected.\nfunc CheckClockDrift() (bool, error) {\n\tdrift, err := sntpDrift(ntpChecks)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\t//fmt.Println(\"drift:\"+ strconv.FormatInt(drift.Milliseconds(),10))\n\tif drift < -driftThreshold || drift > driftThreshold {\n\t\treturn false, nil\n\t}\n\n\treturn true, nil\n}\n\n// sntpDrift does a naive time resolution against an NTP server and returns the\n// measured drift. This method uses the simple version of NTP. It's not precise\n// but should be fine for these purposes.\n//\n// Note, it executes two extra measurements compared to the number of requested\n// ones to be able to discard the two extremes as outliers.\nfunc sntpDrift(measurements int) (time.Duration, error) {\n\t// Resolve the address of the NTP server\n\taddr, err := net.ResolveUDPAddr(\"udp\", ntpPool+\":123\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\t// Construct the time request (empty package with only 2 fields set):\n\t//   Bits 3-5: Protocol version, 3\n\t//   Bits 6-8: Mode of operation, client, 3\n\trequest := make([]byte, 48)\n\trequest[0] = 3<<3 | 3\n\n\t// Execute each of the measurements\n\tvar drifts []time.Duration\n\tfor i := 0; i < measurements+2; i++ {\n\t\t// Dial the NTP server and send the time retrieval request\n\t\tconn, err := net.DialUDP(\"udp\", nil, addr)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\tdefer conn.Close()\n\n\t\tsent := time.Now()\n\t\tif _, err = conn.Write(request); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\t// Retrieve the reply and calculate the elapsed time\n\t\tconn.SetDeadline(time.Now().Add(5 * time.Second))\n\n\t\treply := make([]byte, 48)\n\t\tif _, err = conn.Read(reply); err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\telapsed := time.Since(sent)\n\n\t\t// Reconstruct the time from the reply data\n\t\tsec := uint64(reply[43]) | uint64(reply[42])<<8 | uint64(reply[41])<<16 | uint64(reply[40])<<24\n\t\tfrac := uint64(reply[47]) | uint64(reply[46])<<8 | uint64(reply[45])<<16 | uint64(reply[44])<<24\n\n\t\tnanosec := sec*1e9 + (frac*1e9)>>32\n\n\t\tt := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nanosec)).Local()\n\n\t\t// Calculate the drift based on an assumed answer time of RRT/2\n\t\tdrifts = append(drifts, sent.Sub(t)+elapsed/2)\n\t}\n\t// Calculate average drif (drop two extremities to avoid outliers)\n\tsort.Sort(durationSlice(drifts))\n\n\tdrift := time.Duration(0)\n\tfor i := 1; i < len(drifts)-1; i++ {\n\t\tdrift += drifts[i]\n\t}\n\treturn drift / time.Duration(measurements), nil\n}\n"
  },
  {
    "path": "packages/utils/utils.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/IBAX-io/go-ibax/packages/common/crypto\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf\"\n\t\"github.com/IBAX-io/go-ibax/packages/conf/syspar\"\n\t\"github.com/IBAX-io/go-ibax/packages/consts\"\n\t\"github.com/IBAX-io/go-ibax/packages/converter\"\n\t\"github.com/pkg/errors\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/theckman/go-flock\"\n)\n\nvar (\n\t// ReturnCh is chan for returns\n\tReturnCh chan string\n\t// CancelFunc is represents cancel func\n\tCancelFunc context.CancelFunc\n\t// DaemonsCount is number of daemons\n\tDaemonsCount int\n)\n\n// GetHTTPTextAnswer returns HTTP answer as a string\nfunc GetHTTPTextAnswer(url string) (string, error) {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"url\": url}).Error(\"cannot get url\")\n\t\treturn \"\", err\n\t}\n\tdefer resp.Body.Close()\n\thtmlData, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError}).Error(\"cannot read response body\")\n\t\treturn \"\", err\n\t}\n\tif resp.StatusCode == http.StatusNotFound {\n\t\terr = fmt.Errorf(`404`)\n\t}\n\treturn string(htmlData), err\n}\n\n// ErrInfoFmt fomats the error message\nfunc ErrInfoFmt(err string, a ...any) error {\n\treturn fmt.Errorf(\"%s (%s)\", fmt.Sprintf(err, a...), Caller(1))\n}\n\n// ErrInfo formats the error message\nfunc ErrInfo(verr any, additionally ...string) error {\n\tvar err error\n\tswitch verr.(type) {\n\tcase error:\n\t\terr = verr.(error)\n\tcase string:\n\t\terr = errors.New(verr.(string))\n\t}\n\tif err != nil {\n\t\tif len(additionally) > 0 {\n\t\t\treturn fmt.Errorf(\"%s # %s (%s)\", err, additionally, Caller(1))\n\t\t}\n\t\treturn fmt.Errorf(\"%s (%s)\", err, Caller(1))\n\t}\n\treturn err\n}\n\n// CallMethod calls the function by its name\nfunc CallMethod(i any, methodName string) any {\n\tvar ptr reflect.Value\n\tvar value reflect.Value\n\tvar finalMethod reflect.Value\n\n\tvalue = reflect.ValueOf(i)\n\n\t// if we start with a pointer, we need to get value pointed to\n\t// if we start with a value, we need to get a pointer to that value\n\tif value.Type().Kind() == reflect.Ptr {\n\t\tptr = value\n\t\tvalue = ptr.Elem()\n\t} else {\n\t\tptr = reflect.New(reflect.TypeOf(i))\n\t\ttemp := ptr.Elem()\n\t\ttemp.Set(value)\n\t}\n\n\t// check for method on value\n\tmethod := value.MethodByName(methodName)\n\tif method.IsValid() {\n\t\tfinalMethod = method\n\t}\n\t// check for method on pointer\n\tmethod = ptr.MethodByName(methodName)\n\tif method.IsValid() {\n\t\tfinalMethod = method\n\t}\n\n\tif finalMethod.IsValid() {\n\t\treturn finalMethod.Call([]reflect.Value{})[0].Interface()\n\t}\n\n\t// return or panic, method not found of either type\n\tlog.WithFields(log.Fields{\"method_name\": methodName, \"type\": consts.NotFound}).Error(\"method not found\")\n\treturn fmt.Errorf(\"method %s not found\", methodName)\n}\n\n// Caller returns the name of the latest function\nfunc Caller(steps int) string {\n\tname := \"?\"\n\tif pc, _, num, ok := runtime.Caller(steps + 1); ok {\n\t\tname = fmt.Sprintf(\"%s :  %d\", filepath.Base(runtime.FuncForPC(pc).Name()), num)\n\t}\n\treturn name\n}\n\n// CopyFileContents copy files\nfunc CopyFileContents(src, dst string) error {\n\tin, err := os.Open(src)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"file_name\": src}).Error(\"opening file\")\n\t\treturn ErrInfo(err)\n\t}\n\tdefer in.Close()\n\tout, err := os.Create(dst)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"file_name\": dst}).Error(\"creating file\")\n\t\treturn ErrInfo(err)\n\t}\n\tdefer func() {\n\t\tcerr := out.Close()\n\t\tif err == nil {\n\t\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"file_name\": dst}).Error(\"closing file\")\n\t\t\terr = cerr\n\t\t}\n\t}()\n\tif _, err = io.Copy(out, in); err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"from_file\": src, \"to_file\": dst}).Error(\"copying from to\")\n\t\treturn ErrInfo(err)\n\t}\n\terr = out.Sync()\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"error\": err, \"type\": consts.IOError, \"file_name\": dst}).Error(\"syncing file\")\n\t}\n\treturn ErrInfo(err)\n}\n\n// CheckSign checks the signature\nfunc CheckSign(publicKeys [][]byte, forSign []byte, signs []byte, nodeKeyOrLogin bool) (bool, error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.PanicRecoveredError, \"error\": r}).Error(\"recovered panic in check sign\")\n\t\t}\n\t}()\n\n\tvar signsSlice [][]byte\n\tif len(forSign) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"for sign is empty\")\n\t\treturn false, ErrInfoFmt(\"len(forSign) == 0\")\n\t}\n\tif len(publicKeys) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"public keys is empty\")\n\t\treturn false, ErrInfoFmt(\"len(publicKeys) == 0\")\n\t}\n\tif len(signs) == 0 {\n\t\tlog.WithFields(log.Fields{\"type\": consts.EmptyObject}).Error(\"signs is empty\")\n\t\treturn false, ErrInfoFmt(\"len(signs) == 0\")\n\t}\n\n\t// node always has only one signature\n\tif nodeKeyOrLogin {\n\t\tsignsSlice = append(signsSlice, signs)\n\t} else {\n\t\tlength, err := converter.DecodeLength(&signs)\n\t\tif err != nil {\n\t\t\tlog.WithFields(log.Fields{\"type\": consts.UnmarshallingError, \"error\": err}).Error(\"decoding signs length\")\n\t\t\treturn false, err\n\t\t}\n\t\tif length > 0 {\n\t\t\tsignsSlice = append(signsSlice, converter.BytesShift(&signs, length))\n\t\t}\n\n\t\tif len(publicKeys) != len(signsSlice) {\n\t\t\tlog.WithFields(log.Fields{\"public_keys_length\": len(publicKeys), \"signs_length\": len(signsSlice), \"type\": consts.SizeDoesNotMatch}).Error(\"public keys and signs slices lengths does not match\")\n\t\t\treturn false, fmt.Errorf(\"sign error publicKeys length %d != signsSlice length %d\", len(publicKeys), len(signsSlice))\n\t\t}\n\t}\n\n\treturn crypto.Verify(publicKeys[0], forSign, signsSlice[0])\n}\n\n// GetCurrentDir returns the current directory\nfunc GetCurrentDir() string {\n\tdir, err := filepath.Abs(filepath.Dir(os.Args[0]))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Warning(\"getting current dir\")\n\t\treturn \".\"\n\t}\n\treturn dir\n}\n\n// ShellExecute runs cmdline\nfunc ShellExecute(cmdline string) {\n\ttime.Sleep(500 * time.Millisecond)\n\tswitch runtime.GOOS {\n\tcase \"linux\":\n\t\texec.Command(\"xdg-open\", cmdline).Start()\n\tcase \"windows\":\n\t\texec.Command(`rundll32.exe`, `url.dll,FileProtocolHandler`, cmdline).Start()\n\tcase \"darwin\":\n\t\texec.Command(\"open\", cmdline).Start()\n\t}\n}\n\n// GetParent returns the information where the call of function happened\nfunc GetParent() string {\n\tparent := \"\"\n\tfor i := 2; ; i++ {\n\t\tvar name string\n\t\tif pc, _, num, ok := runtime.Caller(i); ok {\n\t\t\tname = filepath.Base(runtime.FuncForPC(pc).Name())\n\t\t\tfile, line := runtime.FuncForPC(pc).FileLine(pc)\n\t\t\tif i > 5 || name == \"runtime.goexit\" {\n\t\t\t\tbreak\n\t\t\t} else {\n\t\t\t\tparent += fmt.Sprintf(\"%s:%d -> %s:%d / \", filepath.Base(file), line, name, num)\n\t\t\t}\n\t\t}\n\t}\n\treturn parent\n}\n\n// GetNodeKeys returns node private key and public key\nfunc GetNodeKeys() (string, string) {\n\treturn hex.EncodeToString(syspar.GetNodePrivKey()),\n\t\thex.EncodeToString(syspar.GetNodePubKey())\n}\n\nfunc GetNodePrivateKey() ([]byte, error) {\n\tdata, err := os.ReadFile(filepath.Join(conf.Config.DirPathConf.KeysDir, consts.NodePrivateKeyFilename))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.IOError, \"error\": err}).Error(\"reading node private key from file\")\n\t\treturn nil, err\n\t}\n\tprivateKey, err := hex.DecodeString(string(data))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"type\": consts.ConversionError, \"error\": err}).Error(\"decoding private key from hex\")\n\t\treturn nil, err\n\t}\n\treturn privateKey, nil\n}\n\nfunc GetHostPort(h string) string {\n\tif strings.Contains(h, \":\") {\n\t\treturn h\n\t}\n\treturn fmt.Sprintf(\"%s:%d\", h, consts.DefaultTcpPort)\n}\n\nfunc CreateDirIfNotExists(dir string, mode os.FileMode) error {\n\tif _, err := os.Stat(dir); os.IsNotExist(err) {\n\t\terr := os.Mkdir(dir, mode)\n\t\tif err != nil {\n\t\t\treturn errors.Wrapf(err, \"creating dir %s\", dir)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc LockOrDie(dir string) *flock.Flock {\n\tf := flock.New(dir)\n\tsuccess, err := f.TryLock()\n\tif err != nil {\n\t\tlog.WithError(err).Fatal(\"Locking go-ibax\")\n\t}\n\n\tif !success {\n\t\tlog.Fatal(\"Go-ibax is locked\")\n\t}\n\n\treturn f\n}\n\nfunc ShuffleSlice(slice []string) {\n\tfor i := range slice {\n\t\tj := rand.Intn(i + 1)\n\t\tslice[i], slice[j] = slice[j], slice[i]\n\t}\n}\n\n// MakeDirectory makes directory if is not exists\nfunc MakeDirectory(dir string) error {\n\tif _, err := os.Stat(dir); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn os.Mkdir(dir, 0775)\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc StringInSlice(slice []string, v string) bool {\n\tfor _, item := range slice {\n\t\tif v == item {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc ToSnakeCase(s string) string {\n\tvar (\n\t\tin  = []rune(s)\n\t\tout = make([]rune, 0, len(in))\n\t)\n\tfor i, c := range in {\n\t\tif unicode.IsUpper(c) {\n\t\t\tif i > 0 && ((i+1 < len(in) && unicode.IsLower(in[i+1])) || unicode.IsLower(in[i-1])) {\n\t\t\t\tout = append(out, '_')\n\t\t\t}\n\t\t\tc = unicode.ToLower(c)\n\t\t}\n\t\tout = append(out, c)\n\t}\n\treturn string(out)\n}\n"
  },
  {
    "path": "packages/utils/utils_test.go",
    "content": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) IBAX. All rights reserved.\n *  See LICENSE in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestToSnakeCase(t *testing.T) {\n\tcases := []struct {\n\t\targ, expected string\n\t}{\n\t\t{\"Contains\", \"contains\"},\n\t\t{\"AddressToId\", \"address_to_id\"},\n\t\t{\"HMac\", \"h_mac\"},\n\t\t{\"JSONEncode\", \"json_encode\"},\n\t\t{\"Hash\", \"hash\"},\n\t\t{\"PubToID\", \"pub_to_id\"},\n\t}\n\tfor _, tt := range cases {\n\t\tassert.Equal(t, tt.expected, ToSnakeCase(tt.arg))\n\t}\n}\n\nfunc TestNtp(t *testing.T) {\n\tfor i := 0; i < 1000; i++ {\n\t\tst := time.Now()\n\t\tb, err := CheckClockDrift()\n\t\tet := time.Now()\n\t\tdr := et.Sub(st)\n\t\tfmt.Println(\"dr:\" + dr.String())\n\t\tassert.Error(t, err, nil)\n\t\tif b {\n\t\t\tfmt.Println(\"time ok\")\n\t\t} else {\n\t\t\tfmt.Println(\"time not ok\")\n\t\t}\n\t\ttime.Sleep(2 * time.Second)\n\t}\n}\n"
  },
  {
    "path": "tools/desync_monitor/config/config.go",
    "content": "package config\n\nimport (\n\t\"github.com/BurntSushi/toml\"\n)\n\ntype Daemon struct {\n\tDaemonMode     bool `toml:\"daemon\"`\n\tQueryingPeriod int  `toml:\"querying_period\"`\n}\n\ntype Config struct {\n\tDaemon    Daemon   `toml:\"daemon\"`\n\tNodesList []string `toml:\"nodes_list\"`\n}\n\nfunc (c *Config) Read(fileName string) error {\n\t_, err := toml.DecodeFile(fileName, c)\n\treturn err\n}\n"
  },
  {
    "path": "tools/desync_monitor/config.toml.temp",
    "content": "nodes_list = [\n    #    \"http://127.0.0.1:7079\",\n    #    \"http://127.0.0.1:2079\",\n    #    \"http://127.0.0.1:3079\",\n]\n[Daemon]\n    Daemon = true\n    querying_period = 4"
  },
  {
    "path": "tools/desync_monitor/main.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/IBAX-io/go-ibax/tools/desync_monitor/config\"\n\t\"github.com/IBAX-io/go-ibax/tools/desync_monitor/query\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\nconst confPathFlagName = \"confPath\"\nconst nodesListFlagName = \"nodesList\"\nconst daemonModeFlagName = \"daemonMode\"\nconst queryingPeriodFlagName = \"queryingPeriod\"\n\nvar configPath = flag.String(confPathFlagName, \"config.toml\", \"path to desync monitor config\")\nvar nodesList = flag.String(nodesListFlagName, \"127.0.0.1:7079\", \"which nodes to query, in format url1,url2,url3\")\nvar daemonMode = flag.Bool(daemonModeFlagName, false, \"start as daemon\")\nvar queryingPeriod = flag.Int(queryingPeriodFlagName, 1, \"period of querying nodes in seconds, if started as daemon\")\n\nfunc minElement(slice []int64) int64 {\n\tvar min int64 = math.MaxInt64\n\tfor _, blockID := range slice {\n\t\tif blockID < min {\n\t\t\tmin = blockID\n\t\t}\n\t}\n\treturn min\n}\n\nfunc flagsOverrideConfig(conf *config.Config) {\n\tflag.Visit(func(flag *flag.Flag) {\n\t\tswitch flag.Name {\n\t\tcase nodesListFlagName:\n\t\t\tnodesList := strings.Split(*nodesList, \",\")\n\t\t\tconf.NodesList = nodesList\n\t\tcase daemonModeFlagName:\n\t\t\tconf.Daemon.DaemonMode = *daemonMode\n\t\tcase queryingPeriodFlagName:\n\t\t\tconf.Daemon.QueryingPeriod = *queryingPeriod\n\t\t}\n\t})\n}\n\nfunc monitor(conf *config.Config) {\n\tmaxBlockIDs, err := query.MaxBlockIDs(conf.NodesList)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"err\": err}).Error(\"on sending max block request\")\n\t\treturn\n\t}\n\n\tlog.Infoln(\"max blocks \", maxBlockIDs)\n\n\tblockInfos, err := query.BlockInfo(conf.NodesList, minElement(maxBlockIDs))\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"err\": err}).Error(\"on sending block info request\")\n\t\treturn\n\t}\n\n\thash2Node := map[string][]string{}\n\tfor node, blockInfo := range blockInfos {\n\t\trollbacksHash := fmt.Sprintf(\"%d: %x\", blockInfo.BlockID, blockInfo.RollbacksHash)\n\t\tif _, ok := hash2Node[rollbacksHash]; !ok {\n\t\t\thash2Node[rollbacksHash] = []string{}\n\t\t}\n\t\thash2Node[rollbacksHash] = append(hash2Node[rollbacksHash], node)\n\t}\n\n\tlog.Infof(\"requested nodes: %v\", conf.NodesList)\n\n\tif len(hash2Node) <= 1 {\n\t\tlog.Infoln(\"nodes synced\")\n\t\treturn\n\t}\n\n\thash2NodeStrResults := []string{}\n\tfor k, v := range hash2Node {\n\t\thash2NodeStrResults = append(hash2NodeStrResults, fmt.Sprintf(\"%s: %s\", k, v))\n\t}\n\n\tlog.Infof(\"nodes unsynced. Rollback hashes are: %s\", strings.Join(hash2NodeStrResults, \", \"))\n}\n\nfunc main() {\n\tflag.Parse()\n\tconf := &config.Config{}\n\tif err := conf.Read(*configPath); err != nil {\n\t\tlog.WithError(err).Fatal(\"reading config\")\n\t}\n\n\tflagsOverrideConfig(conf)\n\n\tif conf.Daemon.DaemonMode {\n\t\tlog.Infoln(\"MODE: daemon\")\n\t\tticker := time.NewTicker(time.Second * time.Duration(conf.Daemon.QueryingPeriod))\n\t\tfor range ticker.C {\n\t\t\tmonitor(conf)\n\t\t}\n\t} else {\n\t\tlog.Println(\"MODE: single request\")\n\t\tmonitor(conf)\n\t}\n}\n"
  },
  {
    "path": "tools/desync_monitor/query/query.go",
    "content": "package query\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nconst maxBlockIDEndpoint = \"/api/v2/maxblockid\"\nconst blockInfoEndpoint = \"/api/v2/block/%d\"\n\ntype MaxBlockID struct {\n\tMaxBlockID int64 `json:\"max_block_id\"`\n}\n\ntype blockInfoResult struct {\n\tBlockID       int64  `json:\"block_id\"`\n\tHash          []byte `json:\"hash\"`\n\tEcosystemID   int64  `json:\"ecosystem_id\"`\n\tKeyID         int64  `json:\"key_id\"`\n\tTime          int64  `json:\"time\"`\n\tTx            int32  `json:\"tx_count\"`\n\tRollbacksHash []byte `json:\"rollbacks_hash\"`\n}\n\nfunc MaxBlockIDs(nodesList []string) ([]int64, error) {\n\twg := sync.WaitGroup{}\n\tworkResults := ConcurrentMap{m: map[string]any{}}\n\tfor _, nodeUrl := range nodesList {\n\t\twg.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer wg.Done()\n\t\t\tmaxBlockID := &MaxBlockID{}\n\t\t\tif err := sendGetRequest(url+maxBlockIDEndpoint, maxBlockID); err != nil {\n\t\t\t\tworkResults.Set(url, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tworkResults.Set(url, maxBlockID.MaxBlockID)\n\t\t}(nodeUrl)\n\t}\n\twg.Wait()\n\tmaxBlockIds := []int64{}\n\tfor _, result := range workResults.m {\n\t\tswitch res := result.(type) {\n\t\tcase int64:\n\t\t\tmaxBlockIds = append(maxBlockIds, res)\n\t\tcase error:\n\t\t\treturn nil, res\n\t\t}\n\t}\n\treturn maxBlockIds, nil\n}\n\nfunc BlockInfo(nodesList []string, blockID int64) (map[string]*blockInfoResult, error) {\n\twg := sync.WaitGroup{}\n\tworkResults := ConcurrentMap{m: map[string]any{}}\n\tfor _, nodeUrl := range nodesList {\n\t\twg.Add(1)\n\t\tgo func(url string) {\n\t\t\tdefer wg.Done()\n\t\t\tblockInfo := &blockInfoResult{BlockID: blockID}\n\t\t\tif err := sendGetRequest(url+fmt.Sprintf(blockInfoEndpoint, blockID), blockInfo); err != nil {\n\t\t\t\tworkResults.Set(url, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tworkResults.Set(url, blockInfo)\n\t\t}(nodeUrl)\n\t}\n\twg.Wait()\n\tresult := map[string]*blockInfoResult{}\n\tfor nodeUrl, blockInfoOrError := range workResults.m {\n\t\tswitch res := blockInfoOrError.(type) {\n\t\tcase error:\n\t\t\treturn nil, res\n\t\tcase *blockInfoResult:\n\t\t\tresult[nodeUrl] = res\n\t\t}\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "tools/desync_monitor/query/utils.go",
    "content": "package query\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"sync\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\ntype ConcurrentMap struct {\n\tm  map[string]any\n\tmu sync.RWMutex\n}\n\nfunc (c *ConcurrentMap) Set(key string, value any) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\tc.m[key] = value\n}\n\nfunc (c *ConcurrentMap) Get(key string) (bool, any) {\n\tc.mu.RLock()\n\tdefer c.mu.RUnlock()\n\tres, ok := c.m[key]\n\treturn ok, res\n}\n\nfunc sendGetRequest(url string, v any) error {\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"url\": url, \"error\": err}).Error(\"get requesting url\")\n\t\treturn err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\terr := fmt.Errorf(\"status code is not OK %d\", resp.StatusCode)\n\t\tlog.WithFields(log.Fields{\"url\": url, \"error\": err}).Error(\"incorrect status code\")\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\tlog.WithFields(log.Fields{\"url\": url, \"error\": err}).Error(\"reading response body\")\n\t\treturn err\n\t}\n\tif err := json.Unmarshal(data, v); err != nil {\n\t\tlog.WithFields(log.Fields{\"data\": string(data), \"error\": err}).Error(\"unmarshalling json to struct\")\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  }
]