├── .circleci ├── config.yml └── main.sh ├── .gitignore ├── .idea └── vcs.xml ├── LICENSE ├── LICENSE-HEADER ├── NETWORK-TOU.md ├── README.md ├── build-binaries.sh ├── build.sh ├── config.go ├── crypto └── digest │ └── receipt_proof.go ├── docker.go ├── docker_test.go ├── gammacli-linux-install-v0.7.0.sh ├── go.mod ├── go.sum ├── help.go ├── is_ready.go ├── jsoncodec ├── args.go ├── args_test.go ├── config.go ├── events.go ├── keys.go ├── read.go ├── send_tx.go ├── tx_proof.go └── tx_status.go ├── keys.go ├── main.go ├── marketplace ├── gamma-devkit-google-deployment-guide.md ├── images │ ├── step01.png │ ├── step02.png │ ├── step03.png │ ├── step04.png │ ├── step05.png │ ├── step06.png │ ├── step07.png │ ├── step08.png │ ├── step09.png │ ├── step10.png │ ├── step11.png │ ├── step12.png │ ├── step13.png │ ├── step14.png │ ├── step15.png │ ├── step16.png │ ├── step17.png │ └── step18.png └── setup.sh ├── public_api.go ├── test.sh └── test ├── _arguments └── arguments.go ├── _corrupt └── corrupt.go ├── _counter └── contract.go ├── arguments-check.json ├── arguments-get.json ├── arguments_test.go ├── config_override_test.go ├── counter-add.json ├── counter-get.json ├── deploy_test.go ├── generate_config.py ├── get-balance.json ├── harness.go ├── help_test.go ├── restart_test.go ├── token_test.go ├── transfer-direct.json ├── transfer.json └── upgrade_test.go /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | machine: true 5 | steps: 6 | - checkout 7 | - run: ./.circleci/main.sh 8 | 9 | workflows: 10 | version: 2 11 | build: 12 | jobs: 13 | - build 14 | -------------------------------------------------------------------------------- /.circleci/main.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | PROJ_PATH=`pwd` 4 | GO_VERSION="1.12.6" 5 | 6 | # First let's install Go 1.11 7 | echo "Installing Go $GO_VERSION..." 8 | cd /tmp 9 | 10 | curl -O https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz 11 | sudo tar -xf go${GO_VERSION}.linux-amd64.tar.gz 12 | 13 | # Uninstall older version of Go 14 | sudo rm -rf /usr/local/go 15 | sudo mv go /usr/local 16 | 17 | export GOROOT=/usr/local/go 18 | export PATH=$GOPATH/bin:$GOROOT/bin:$PATH 19 | 20 | cd $PROJ_PATH 21 | 22 | ./test.sh 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go ### 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, build with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | ### Intellij/GoLand ### 16 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 17 | # Ignore all XML files except run configurations 18 | .idea/**/*.xml 19 | !.idea/runConfigurations/*.xml 20 | 21 | .idea/**/*.iml 22 | 23 | ## To re-enable a specific XML file within .idea, use the following pattern (remove the leading #) 24 | # !.idea/vcs.xml 25 | 26 | # CMake 27 | cmake-build-debug/ 28 | 29 | # Mongo Explorer plugin: 30 | .idea/**/mongoSettings.xml 31 | 32 | ## File-based project format: 33 | *.iws 34 | 35 | ## Plugin-specific files: 36 | 37 | # IntelliJ 38 | /out/ 39 | 40 | # mpeltonen/sbt-idea plugin 41 | .idea_modules/ 42 | 43 | # JIRA plugin 44 | atlassian-ide-plugin.xml 45 | 46 | # Cursive Clojure plugin 47 | .idea/replstate.xml 48 | 49 | # Ruby plugin and RubyMine 50 | /.rakeTasks 51 | 52 | # Crashlytics plugin (for Android Studio and IntelliJ) 53 | com_crashlytics_export_strings.xml 54 | crashlytics.properties 55 | crashlytics-build.properties 56 | fabric.properties 57 | 58 | ### Intellij Patch ### 59 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 60 | 61 | # *.iml 62 | # modules.xml 63 | # .idea/misc.xml 64 | # *.ipr 65 | 66 | # Sonarlint plugin 67 | .idea/sonarlint 68 | 69 | .DS_Store 70 | 71 | # Logs 72 | *.log 73 | logs/ 74 | 75 | orbs-test-keys.json 76 | _bin -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Orbs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE-HEADER: -------------------------------------------------------------------------------- 1 | Copyright 2019 the gamma-cli authors 2 | This file is part of the gamma-cli library in the Orbs project. 3 | 4 | This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | The above notice should be included in all copies or substantial portions of the software. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gamma - Personal Orbs Blockchain for Developers 2 | 3 | [![CircleCI](https://circleci.com/gh/orbs-network/gamma-cli.svg?style=svg)](https://circleci.com/gh/orbs-network/gamma-cli) 4 | 5 | Gamma is a personal Orbs blockchain that allows developers to easily test, run and deploy smart contracts. 6 | 7 | `Gamma server` - runs an in-memory virtual chain on top of an Orbs blockchain with several nodes on your local machine. 8 | 9 | `gamma-cli` - command line tool for developers to interact with a Gamma server instance running on their machine. 10 | 11 | 12 | ## Detailed documentation 13 | 14 | The detailed documentation website for Gamma is available here: 15 | 16 | https://orbs.gitbook.io 17 | 18 | ## Quick start 19 | 20 |
21 | Mac 22 | 23 | ### Prerequisites 24 | * Make sure [brew](https://brew.sh/) is available on your machine. 25 | * Make sure [Docker](https://docs.docker.com/docker-for-mac/install/) is installed on your machine. 26 | * If you're planning to develop your own smart contracts in Go 27 | * Install [Go language](https://golang.org/doc/install#macos) 28 | * Install the [Orbs Smart Contract SDK](https://github.com/orbs-network/orbs-contract-sdk#installation) 29 | 30 | ### Installation 31 | 1. To install the command line tool, run the following command in terminal: 32 | ``` 33 | brew install orbs-network/devtools/gamma-cli 34 | ``` 35 | > To verify the installation, run in terminal `gamma-cli version` 36 | 37 | 2. Gamma server will automatically be installed the first time you start it with `gamma-cli start-local` 38 | 39 | ### Starting and stopping Gamma server 40 | 41 | * Start Gamma server by running in terminal: 42 | ``` 43 | gamma-cli start-local 44 | ``` 45 | * When finished working with the server, stop it by running in terminal: 46 | ``` 47 | gamma-cli stop-local 48 | ``` 49 | > Note: The local blockchain instance is running in-memory. The next time you start the instance, all contracts and state will disappear from memory and you will need to deploy them again. 50 | 51 |
52 | 53 |
54 | Windows 55 | 56 | ### Prerequisites 57 | * Make sure [Docker](https://www.docker.com/products/docker-desktop) is installed on your machine. 58 | * If you're planning to develop your own smart contracts in Go 59 | * Install [Go language](https://golang.org/doc/install#windows) 60 | * Install the [Orbs Smart Contract SDK](https://github.com/orbs-network/orbs-contract-sdk#installation) 61 | 62 | ### Installation 63 | * Download latest version of Gamma from [releases](https://github.com/orbs-network/gamma-cli/releases) 64 | * Extract the archive to `Program Files` 65 | * Edit `$profile` settings of PowerShell 66 | * Create a file: `C:\Users\\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` or edit it. 67 | * Add the following content: 68 | ```bash 69 | Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser 70 | New-Alias gamma-cli 'C:\Program Files\gammacli-windows-v0.7.0\_bin\gamma-cli.exe' 71 | ``` 72 | * Verify the installation: open PowerShell and run `gamma-cli version`. You should see the current version, e.g. `v0.7.0` 73 | 74 | ### Starting and stopping Gamma server 75 | 76 | * Start Gamma server by running in terminal: 77 | ``` 78 | gamma-cli start-local 79 | ``` 80 | * When finished working with the server, stop it by running in terminal: 81 | ``` 82 | gamma-cli stop-local 83 | ``` 84 | > Note: The local blockchain instance is running in-memory. The next time you start the instance, all contracts and state will disappear from memory and you will need to deploy them again. 85 | 86 |
87 | 88 | 89 | ## Commands 90 | 91 | ``` 92 | Usage: 93 | 94 | gamma-cli COMMAND [OPTIONS] 95 | 96 | Commands: 97 | 98 | start-local start a local Orbs personal blockchain instance listening on port 99 | options: -port 100 | example: gamma-cli start-local -port 8080 101 | 102 | stop-local stop a locally running Orbs personal blockchain instance 103 | 104 | gen-test-keys generate a new batch of 10 test keys and store in orbs-test-keys.json (default filename) 105 | options: -keys [OUTPUT_FILE] 106 | example: gamma-cli gen-test-keys -keys orbs-test-keys.json 107 | 108 | deploy deploy a smart contract with the code specified in the source file 109 | options: -name [CONTRACT_NAME] -signer [ID_FROM_KEYS_JSON] 110 | example: gamma-cli deploy MyToken.go -signer user1 111 | gamma-cli deploy contract.go -name MyToken 112 | 113 | send-tx sign and send the transaction specified in the JSON file 114 | options: -arg# [OVERRIDE_ARG_#] -signer [ID_FROM_KEYS_JSON] 115 | example: gamma-cli send-tx transfer.json -signer user1 116 | gamma-cli send-tx transfer.json -arg2 0x5B63Ca66637316A0D7f84Ebf60E50963c10059aD 117 | 118 | run-query read state or run a read-only contract method as specified in the JSON file 119 | options: -arg# [OVERRIDE_ARG_#] -signer [ID_FROM_KEYS_JSON] 120 | example: gamma-cli run-query get-balance.json -signer user1 121 | gamma-cli run-query get-balance.json -arg1 0x5B63Ca66637316A0D7f84Ebf60E50963c10059aD 122 | 123 | tx-status get the current status of a sent transaction with txid (from send-tx response) 124 | options: 125 | example: gamma-cli tx-status 0xB68fa95B7f397815Ddf41150d79b27a888448a22e08DeAf8600E7a495c406303659f8C3782614660 126 | 127 | tx-proof get cryptographic proof for transaction receipt with txid (from send-tx response) 128 | options: 129 | example: gamma-cli tx-proof 0xB68fa95B7f397815Ddf41150d79b27a888448a22e08DeAf8600E7a495c406303659f8C3782614660 130 | 131 | upgrade-server upgrade to the latest stable version of Gamma server 132 | example: gamma-cli upgrade-server 133 | gamma-cli upgrade-server -env experimental 134 | 135 | logs streams logs from gamma that are printed by smart contract to stdout (i.e. println()) 136 | 137 | version print gamma-cli and Gamma server versions 138 | 139 | help print this help screen 140 | 141 | 142 | Options: 143 | 144 | -config string 145 | path to config file (default "orbs-gamma-config.json") 146 | -env string 147 | environment from config file containing server connection details (default "local") 148 | -keys string 149 | name of the json file containing test keys (default "orbs-test-keys.json") 150 | -name string 151 | name of the smart contract being deployed 152 | -port int 153 | listening port for Gamma server (default "8080") 154 | -signer string 155 | id of the signing key from the test key json (default "user1") 156 | -wait 157 | wait until Gamma server is ready and listening 158 | 159 | Multiple environments (eg. local and testnet) can be defined in orbs-gamma-config.json configuration file. 160 | See https://orbs.gitbook.io for more info. 161 | ``` 162 | 163 | ## Upgrading to latest stable versions (Mac) 164 | 165 | * Upgrade to the latest version of `gamma-cli` by running in terminal: 166 | 167 | ``` 168 | brew upgrade gamma-cli 169 | ``` 170 | 171 | * Upgrade to the latest version of Gamma server by running in terminal: 172 | 173 | ``` 174 | gamma-cli upgrade-server 175 | ``` 176 | 177 | ## Working with latest dev versions (experimental) 178 | 179 | * Upgrade to the latest dev version of `gamma-cli` by running in terminal: 180 | 181 | ``` 182 | brew upgrade gamma-cli --devel 183 | ``` 184 | 185 | * Upgrade to the latest dev version of Gamma server by running in terminal: 186 | 187 | ``` 188 | gamma-cli upgrade-server -env experimental 189 | ``` 190 | 191 | * Start the experimental Gamma server by running in terminal: 192 | 193 | ``` 194 | gamma-cli start-local -env experimental 195 | ``` 196 | 197 | ## Advanced debugging 198 | 199 | * In order to investigate backend issues in Gamma server itself, gain access to the server logs of the currently running instance by running in terminal: 200 | 201 | ``` 202 | docker logs -f orbs-gamma-server 203 | ``` 204 | 205 | ## Working with Gamma server using client SDK 206 | 207 | Instead of deploying contracts and sending transactions using `gamma-cli`, you can also use any of the client SDKs (like [JavaScript Client SDK](https://github.com/orbs-network/orbs-client-sdk-javascript), [Go Client SDK](https://github.com/orbs-network/orbs-client-sdk-go)) to communicate with Gamma server. 208 | 209 | Start Gamma server on some port (eg. 8080), and then use the following endpoint in the client SDK: 210 | 211 | ``` 212 | http://localhost:8080 213 | VIRTUAL_CHAIN_ID = 42 214 | ``` 215 | 216 | Provide the client SDK with virtual chain ID of `42` as this is the pre-defined ID of the virtual chain running inside Gamma server. You can usually see a working example in the [E2E test](https://github.com/orbs-network/orbs-client-sdk-javascript/blob/master/e2e/nodejs/e2e.test.js) of each client SDK. 217 | 218 | ## Installing Gamma Docker image directly 219 | 220 | Instead of installing Gamma server using `gamma-cli`, you can also install Gamma server directly from [Docker Hub](https://hub.docker.com/r/orbsnetwork/gamma/tags). This is particularly useful when running on CI: 221 | 222 | ``` 223 | docker pull orbsnetwork/gamma:v1.3.12 # specific version 224 | docker pull orbsnetwork/gamma # latest stable version 225 | docker pull orbsnetwork/gamma:experimental # latest experimental version 226 | ``` 227 | 228 |   229 | 230 | ## License 231 | 232 | MIT 233 | -------------------------------------------------------------------------------- /build-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf ./_bin 3 | 4 | mkdir -p ./_bin 5 | 6 | VERSION="v0.11.1" 7 | 8 | echo "\n\n*** MAC:" 9 | GOOS=darwin GOARCH=amd64 go build -ldflags "-w -extldflags '-static' -X main.GAMMA_CLI_VERSION=$VERSION" -tags "usergo netgo" -o _bin/gamma-cli 10 | tar -zcvf ./_bin/gammacli-mac-$VERSION.tar.gz ./_bin/gamma-cli 11 | rm ./_bin/gamma-cli 12 | 13 | echo "\n\n*** LINUX (x86-64):" 14 | GOOS=linux GOARCH=amd64 go build -ldflags "-w -extldflags '-static' -X main.GAMMA_CLI_VERSION=$VERSION" -tags "usergo netgo" -o _bin/gamma-cli 15 | tar -zcvf ./_bin/gammacli-linux-x86-64-$VERSION.tar.gz ./_bin/gamma-cli 16 | rm ./_bin/gamma-cli 17 | 18 | echo "\n\n*** LINUX (i386):" 19 | GOOS=linux GOARCH=386 go build -ldflags "-w -extldflags '-static' -X main.GAMMA_CLI_VERSION=$VERSION" -tags "usergo netgo" -o _bin/gamma-cli 20 | tar -zcvf ./_bin/gammacli-linux-i386-$VERSION.tar.gz ./_bin/gamma-cli 21 | rm ./_bin/gamma-cli 22 | 23 | echo "\n\n*** WINDOWS:" 24 | GOOS=windows GOARCH=386 go build -ldflags "-w -extldflags '-static' -X main.GAMMA_CLI_VERSION=$VERSION" -tags "usergo netgo" -o _bin/gamma-cli.exe 25 | zip -r ./_bin/gammacli-windows-$VERSION.zip ./_bin/gamma-cli.exe 26 | rm ./_bin/gamma-cli.exe 27 | 28 | cd ./_bin 29 | 30 | openssl sha256 gammacli-mac-$VERSION.tar.gz >> ./checksums.txt 31 | openssl sha256 gammacli-linux-x86-64-$VERSION.tar.gz >> ./checksums.txt 32 | openssl sha256 gammacli-linux-i386-$VERSION.tar.gz >> ./checksums.txt 33 | openssl sha256 gammacli-windows-$VERSION.zip >> ./checksums.txt 34 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -xe 2 | rm -rf ./_bin 3 | 4 | mkdir -p ./_bin 5 | go build -o _bin/gamma-cli -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "github.com/orbs-network/gamma-cli/jsoncodec" 11 | "io/ioutil" 12 | ) 13 | 14 | func getDefaultLocalConfig() *jsoncodec.ConfEnv { 15 | return &jsoncodec.ConfEnv{ 16 | VirtualChain: 42, 17 | Endpoints: []string{"localhost"}, 18 | } 19 | } 20 | 21 | func getDefaultExperimentalConfig() *jsoncodec.ConfEnv { 22 | return &jsoncodec.ConfEnv{ 23 | VirtualChain: 42, 24 | Endpoints: []string{"localhost"}, 25 | Experimental: true, 26 | } 27 | } 28 | 29 | func getDefaultConfigForEnv(env string) *jsoncodec.ConfEnv { 30 | if env == LOCAL_ENV_ID { 31 | return getDefaultLocalConfig() 32 | } 33 | if env == EXPERIMENTAL_ENV_ID { 34 | return getDefaultExperimentalConfig() 35 | } 36 | return nil 37 | } 38 | 39 | func getEnvironmentFromConfigFile(env string) *jsoncodec.ConfEnv { 40 | bytes, err := ioutil.ReadFile(*flagConfigFile) 41 | if err != nil { 42 | if res := getDefaultConfigForEnv(env); res != nil { 43 | return res 44 | } 45 | die("Could not open config file '%s' containing environment details.\n\n%s", *flagConfigFile, err.Error()) 46 | } 47 | 48 | confFile, err := jsoncodec.UnmarshalConfFile(bytes) 49 | if err != nil { 50 | die("Failed parsing config json file '%s'.\n\n%s", *flagConfigFile, err.Error()) 51 | } 52 | 53 | if len(confFile.Environments) == 0 { 54 | if res := getDefaultConfigForEnv(env); res != nil { 55 | return res 56 | } 57 | die("Key 'Environments' does not contain data in config file '%s'.", *flagConfigFile) 58 | } 59 | 60 | confEnv, found := confFile.Environments[env] 61 | if !found { 62 | if res := getDefaultConfigForEnv(env); res != nil { 63 | return res 64 | } 65 | die("Environment with id '%s' not found in config file '%s'.", env, *flagKeyFile) 66 | } 67 | 68 | return confEnv 69 | } 70 | -------------------------------------------------------------------------------- /crypto/digest/receipt_proof.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package digest 8 | 9 | import ( 10 | "github.com/orbs-network/lean-helix-go" 11 | "github.com/orbs-network/orbs-spec/types/go/primitives" 12 | "github.com/orbs-network/orbs-spec/types/go/protocol" 13 | "github.com/pkg/errors" 14 | ) 15 | 16 | func GetBlockSignersFromReceiptProof(packedProof primitives.PackedReceiptProof) ([]primitives.NodeAddress, error) { 17 | var res []primitives.NodeAddress 18 | receiptProof := protocol.ReceiptProofReader(packedProof) 19 | switch receiptProof.BlockProof().Type() { 20 | case protocol.RESULTS_BLOCK_PROOF_TYPE_LEAN_HELIX: 21 | leanHelixBlockProof := receiptProof.BlockProof().LeanHelix() 22 | memberIds, err := leanhelix.GetMemberIdsFromBlockProof(leanHelixBlockProof) 23 | if err != nil { 24 | return nil, err 25 | } 26 | for _, memberId := range memberIds { 27 | res = append(res, primitives.NodeAddress(memberId)) 28 | } 29 | return res, nil 30 | case protocol.RESULTS_BLOCK_PROOF_TYPE_BENCHMARK_CONSENSUS: 31 | benchmarkConsensusBlockProof := receiptProof.BlockProof().BenchmarkConsensus() 32 | iterator := benchmarkConsensusBlockProof.NodesIterator() 33 | for iterator.HasNext() { 34 | res = append(res, iterator.NextNodes().SenderNodeAddress()) 35 | } 36 | return res, nil 37 | } 38 | return nil, errors.Errorf("unknown block proof type: %v", receiptProof.BlockProof().Type()) 39 | } 40 | -------------------------------------------------------------------------------- /docker.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "bufio" 11 | "encoding/json" 12 | "fmt" 13 | "github.com/pkg/errors" 14 | "io/ioutil" 15 | "net/http" 16 | "os" 17 | "os/exec" 18 | "regexp" 19 | "runtime" 20 | "strconv" 21 | "strings" 22 | ) 23 | 24 | const DOCKER_TAG_NOT_FOUND = "not found" 25 | const DOCKER_TAG_EXPERIMENTAL = "experimental" 26 | 27 | func commandStartLocal(requiredOptions []string) { 28 | commandStartLocalContainer(gammaHandlerOptions(), requiredOptions) 29 | 30 | if prismEnabled() { 31 | commandStartLocalContainer(prismHandlerOptions(), requiredOptions) 32 | } 33 | } 34 | 35 | func commandStopLocal(requiredOptions []string) { 36 | commandStopLocalContainer(gammaHandlerOptions(), requiredOptions) 37 | 38 | if prismEnabled() { 39 | commandStopLocalContainer(prismHandlerOptions(), requiredOptions) 40 | } 41 | } 42 | 43 | func commandUpgrade(requiredOptions []string) { 44 | gammaUpgraded := commandUpgradeImage(gammaHandlerOptions(), requiredOptions) 45 | prismUpgraded := commandUpgradeImage(prismHandlerOptions(), requiredOptions) 46 | if (gammaUpgraded || prismUpgraded) && 47 | isDockerContainerRunning(gammaHandlerOptions().containerName) { 48 | if !isDockerContainerRunning(prismHandlerOptions().containerName) { 49 | noPrism := true 50 | flagNoUi = &noPrism 51 | } 52 | 53 | commandStopLocal(requiredOptions) 54 | commandStartLocal(requiredOptions) 55 | } 56 | } 57 | 58 | func commandStartLocalContainer(dockerOptions handlerOptions, requiredOptions []string) { 59 | version := verifyDockerInstalled(dockerOptions, dockerOptions.dockerRegistryTagsUrl) 60 | 61 | if !doesFileExist(*flagKeyFile) { 62 | commandGenerateTestKeys(nil) 63 | } 64 | 65 | if isDockerContainerRunning(dockerOptions.containerName) { 66 | log(` 67 | ********************************************************************************* 68 | %s is already running! 69 | 70 | Run 'gamma-cli help' in terminal to learn how to interact with this instance. 71 | 72 | ********************************************************************************** 73 | `, dockerOptions.name) 74 | exit() 75 | } 76 | 77 | if err := createDockerNetwork(); err != nil { 78 | die("could not create docker network gamma: %s", err) 79 | } 80 | 81 | p := fmt.Sprintf("%d:%d", dockerOptions.port, dockerOptions.containerPort) 82 | run := fmt.Sprintf("%s:%s", dockerOptions.dockerRepo, version) 83 | args := []string { 84 | "run", "-d", 85 | "--name", dockerOptions.containerName, 86 | "-p", p, 87 | "--network", "gamma", 88 | } 89 | for _, value := range dockerOptions.env { 90 | args = append(args, "-e", value) 91 | } 92 | args = append(args, run) 93 | args = append(args, dockerOptions.dockerCmd...) 94 | 95 | out, err := exec.Command("docker", args...).CombinedOutput() 96 | if err != nil { 97 | die("Could not exec 'docker run' command.\n\n%s", out) 98 | } 99 | 100 | if !isDockerContainerRunning(dockerOptions.containerName) { 101 | die("Could not run docker image.") 102 | } 103 | 104 | if *flagWait { 105 | waitUntilDockerIsReadyAndListening(IS_READY_TOTAL_WAIT_TIMEOUT) 106 | } 107 | 108 | log(` 109 | ********************************************************************************* 110 | %s %s is running! 111 | 112 | Local blockchain instance started and listening on port %d. 113 | Run 'gamma-cli help' in terminal to learn how to interact with this instance. 114 | 115 | ********************************************************************************** 116 | `, dockerOptions.name, version, dockerOptions.port) 117 | } 118 | 119 | func commandStopLocalContainer(dockerOptions handlerOptions, requiredOptions []string) { 120 | verifyDockerInstalled(dockerOptions, dockerOptions.dockerRegistryTagsUrl) 121 | 122 | out, err := exec.Command("docker", "stop", dockerOptions.containerName).CombinedOutput() 123 | if err != nil { 124 | log("%s server is already stopped.\n", dockerOptions.name) 125 | } 126 | 127 | out, err = exec.Command("docker", "rm", "-f", dockerOptions.containerName).CombinedOutput() 128 | if err != nil { 129 | log("Could not remove docker container.\n\n%s", out) 130 | } 131 | 132 | if isDockerContainerRunning(dockerOptions.containerName) { 133 | die("Could not stop docker container.") 134 | } 135 | 136 | log(` 137 | ********************************************************************************* 138 | %s stopped. 139 | 140 | A local blockchain instance is running in-memory. 141 | The next time you start the instance, all contracts and state will disappear. 142 | 143 | ********************************************************************************** 144 | `, dockerOptions.name) 145 | } 146 | 147 | func commandUpgradeImage(dockerOptions handlerOptions, requiredOptions []string) bool { 148 | currentTag := verifyDockerInstalled(dockerOptions, dockerOptions.dockerRegistryTagsUrl) 149 | latestTag := getLatestDockerTag(dockerOptions.dockerRegistryTagsUrl) 150 | 151 | if !isExperimental() && cmpTags(latestTag, currentTag) <= 0 { 152 | log("Current %s stable version %s does not require upgrade.", dockerOptions.name, currentTag) 153 | } else { 154 | log("Downloading latest %s version %s:\n", dockerOptions.name, latestTag) 155 | cmd := exec.Command("docker", "pull", fmt.Sprintf("%s:%s", dockerOptions.dockerRepo, latestTag)) 156 | output, _ := cmd.CombinedOutput() 157 | log(string(output)) 158 | if !strings.Contains(string(output), "Image is up to date") { 159 | return true 160 | } 161 | } 162 | return false 163 | } 164 | 165 | func showLogs(requiredOptions []string) { 166 | dockerOptions := gammaHandlerOptions() 167 | verifyDockerInstalled(dockerOptions, dockerOptions.dockerRegistryTagsUrl) 168 | 169 | cmd := exec.Command("docker", "logs", "-f", "--tail=20", dockerOptions.containerName) 170 | stdout, err := cmd.StderrPipe() // println() and print() go to stderr 171 | if err != nil { 172 | die("could not read gamma server docker logs: %s", err) 173 | } 174 | 175 | if err := cmd.Start(); err != nil { 176 | die("could not start docker logs command: %s", err) 177 | } 178 | 179 | scanner := bufio.NewScanner(stdout) 180 | for scanner.Scan() { 181 | fmt.Println(scanner.Text()) 182 | } 183 | if err := scanner.Err(); err != nil { 184 | die("error reading gamma server docker logs: %s", err) 185 | } 186 | } 187 | 188 | // TODO remove dockerRegistryUrl as separate parameter 189 | func verifyDockerInstalled(dockerOptions handlerOptions, dockerRegistryTagUrl string) string { 190 | out, err := exec.Command("docker", "images", dockerOptions.dockerRepo).CombinedOutput() 191 | if err != nil { 192 | if runtime.GOOS == "darwin" { 193 | die("Docker is required but not running. Is it installed on your machine?\n\nInstall from: https://docs.docker.com/docker-for-mac/install/") 194 | } else { 195 | die("Docker is required but not running. Is it installed on your machine?\n\nInstall from: https://docs.docker.com/install/") 196 | } 197 | } 198 | 199 | existingTag := extractTagFromDockerImagesOutput(dockerOptions.dockerRepo, string(out)) 200 | if existingTag != DOCKER_TAG_NOT_FOUND { 201 | return existingTag 202 | } 203 | 204 | latestTag := getLatestDockerTag(dockerRegistryTagUrl) 205 | 206 | log("%s image is not installed, downloading version %s:\n", dockerOptions.name, latestTag) 207 | cmd := exec.Command("docker", "pull", fmt.Sprintf("%s:%s", dockerOptions.dockerRepo, latestTag)) 208 | cmd.Stdout = os.Stdout 209 | cmd.Stderr = os.Stderr 210 | cmd.Run() 211 | log("") 212 | 213 | out, err = exec.Command("docker", "images", dockerOptions.dockerRepo).CombinedOutput() 214 | if err != nil || strings.Count(string(out), "\n") == 1 { 215 | die("Could not download docker image.") 216 | } 217 | return extractTagFromDockerImagesOutput(dockerOptions.dockerRepo, string(out)) 218 | } 219 | 220 | func isDockerContainerRunning(containerName string) bool { 221 | out, err := exec.Command("docker", "ps", "-f", fmt.Sprintf("name=%s", containerName)).CombinedOutput() 222 | if err != nil { 223 | return false 224 | } 225 | return strings.Count(string(out), "\n") > 1 226 | } 227 | 228 | func extractTagFromDockerImagesOutput(dockerRepo string, out string) string { 229 | pattern := fmt.Sprintf(`%s\s+(v\S+)`, regexp.QuoteMeta(dockerRepo)) 230 | if isExperimental() { 231 | pattern = fmt.Sprintf(`%s\s+(%s)`, regexp.QuoteMeta(dockerRepo), regexp.QuoteMeta(DOCKER_TAG_EXPERIMENTAL)) 232 | } 233 | re := regexp.MustCompile(pattern) 234 | res := re.FindStringSubmatch(out) 235 | if len(res) < 2 { 236 | return DOCKER_TAG_NOT_FOUND 237 | } 238 | return res[1] 239 | } 240 | 241 | func getLatestDockerTag(dockerRegistryTagsUrl string) string { 242 | if isExperimental() { 243 | return DOCKER_TAG_EXPERIMENTAL 244 | } 245 | resp, err := http.Get(dockerRegistryTagsUrl) 246 | if err != nil { 247 | die("Cannot connect to docker registry to get image list.") 248 | } 249 | defer resp.Body.Close() 250 | bytes, err := ioutil.ReadAll(resp.Body) 251 | if err != nil || len(bytes) == 0 { 252 | die("Bad image list response from docker registry.") 253 | } 254 | tag, err := extractLatestTagFromDockerHubResponse(bytes) 255 | if err != nil { 256 | die("Cannot parse image list response from docker registry.") 257 | } 258 | return tag 259 | } 260 | 261 | type dockerHubTagsJson struct { 262 | Results []*struct { 263 | Name string 264 | } 265 | } 266 | 267 | func extractLatestTagFromDockerHubResponse(responseBytes []byte) (string, error) { 268 | var response *dockerHubTagsJson 269 | err := json.Unmarshal(responseBytes, &response) 270 | if err != nil { 271 | return "", err 272 | } 273 | maxTag := "" 274 | for _, result := range response.Results { 275 | if cmpTags(result.Name, maxTag) > 0 { 276 | maxTag = result.Name 277 | } 278 | } 279 | if maxTag == "" { 280 | return "", errors.New("no valid tags found") 281 | } 282 | return maxTag, nil 283 | } 284 | 285 | func isExperimental() bool { 286 | if *flagEnv == LOCAL_ENV_ID { 287 | return false 288 | } 289 | if *flagEnv == EXPERIMENTAL_ENV_ID { 290 | return true 291 | } 292 | // allow custom experimental configs (like for docker ci) 293 | return getEnvironmentFromConfigFile(*flagEnv).Experimental 294 | } 295 | 296 | func cmpTags(t1, t2 string) int { 297 | re := regexp.MustCompile(`v(\d+)\.(\d+)\.(\d+)`) 298 | m1 := re.FindStringSubmatch(t1) 299 | if len(m1) < 4 { 300 | return -1 301 | } 302 | m2 := re.FindStringSubmatch(t2) 303 | if len(m2) < 4 { 304 | return 1 305 | } 306 | diff := atoi(m1[1]) - atoi(m2[1]) 307 | if diff != 0 { 308 | return diff 309 | } 310 | diff = atoi(m1[2]) - atoi(m2[2]) 311 | if diff != 0 { 312 | return diff 313 | } 314 | return atoi(m1[3]) - atoi(m2[3]) 315 | } 316 | 317 | func atoi(num string) int { 318 | res, err := strconv.Atoi(num) 319 | if err != nil { 320 | return 0 321 | } 322 | return res 323 | } 324 | 325 | func createDockerNetwork() error { 326 | out, err := exec.Command("docker", "network", "ls", "--filter", "name=gamma", "-q").CombinedOutput() 327 | if err != nil { 328 | return err 329 | } 330 | 331 | if len(out) == 0 { 332 | _, err := exec.Command("docker", "network", "create", "gamma").CombinedOutput() 333 | if err != nil { 334 | return err 335 | } 336 | } 337 | 338 | return nil 339 | } 340 | 341 | func prismEnabled() bool { 342 | return !*flagNoUi 343 | } -------------------------------------------------------------------------------- /docker_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "github.com/stretchr/testify/require" 11 | "testing" 12 | ) 13 | 14 | func TestExtractLatestTagFromDockerHubResponse(t *testing.T) { 15 | tests := []struct { 16 | name string 17 | input string 18 | expected string 19 | }{ 20 | { 21 | name: "HappyFlow", 22 | input: `{"count": 2, "next": null, "previous": null, "results": [{"name": "v0.4.2", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40717129, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:32.560968Z", "image_id": null, "v2": true}, {"name": "v0.7.0", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40686462, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:27.625449Z", "image_id": null, "v2": true}]}`, 23 | expected: "v0.7.0", 24 | }, 25 | { 26 | name: "HappyFlowReversed", 27 | input: `{"count": 2, "next": null, "previous": null, "results": [{"name": "v1.2.3", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40717129, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:32.560968Z", "image_id": null, "v2": true}, {"name": "v0.7.0", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40686462, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:27.625449Z", "image_id": null, "v2": true}]}`, 28 | expected: "v1.2.3", 29 | }, 30 | { 31 | name: "Empty", 32 | input: ``, 33 | expected: "", 34 | }, 35 | { 36 | name: "NoResults", 37 | input: `{"count": 0, "next": null, "previous": null, "results": []}`, 38 | expected: "", 39 | }, 40 | { 41 | name: "Corrupt", 42 | input: `{"count": 2, "next": null, "previous": null, "results": [{"name": "v0.4.2", "full_size": 126289039, "ima`, 43 | expected: "", 44 | }, 45 | { 46 | name: "NonSemver", 47 | input: `{"count": 2, "next": null, "previous": null, "results": [{"name": "latest", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40717129, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:32.560968Z", "image_id": null, "v2": true}, {"name": "v0.7.0", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40686462, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:27.625449Z", "image_id": null, "v2": true}]}`, 48 | expected: "v0.7.0", 49 | }, 50 | { 51 | name: "Experimental", 52 | input: `{"count": 2, "next": null, "previous": null, "results": [{"name": "experimental", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40717129, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:32.560968Z", "image_id": null, "v2": true}, {"name": "v0.7.0", "full_size": 126289039, "images": [{"size": 126289039, "architecture": "amd64", "variant": null, "features": null, "os": "linux", "os_version": null, "os_features": null}], "id": 40686462, "repository": 6341803, "creator": 4691149, "last_updater": 4691149, "last_updated": "2018-11-26T14:02:27.625449Z", "image_id": null, "v2": true}]}`, 53 | expected: "v0.7.0", 54 | }, 55 | } 56 | for _, tt := range tests { 57 | t.Run(tt.name, func(t *testing.T) { 58 | tag, err := extractLatestTagFromDockerHubResponse([]byte(tt.input)) 59 | if tt.expected == "" { 60 | require.Error(t, err, "extract should return an error") 61 | } else { 62 | require.NoError(t, err, "extract should not return an error") 63 | require.Equal(t, tt.expected, tag, "extracted tag should match") 64 | } 65 | }) 66 | } 67 | } 68 | 69 | func TestCmpTags(t *testing.T) { 70 | tests := []struct { 71 | name string 72 | first string 73 | second string 74 | expected int 75 | }{ 76 | { 77 | name: "Equal", 78 | first: "v1.2.3", 79 | second: "v1.2.3", 80 | expected: 0, // latest, current -> no upgrade 81 | }, 82 | { 83 | name: "FirstNewer(patch)", 84 | first: "v1.2.3", 85 | second: "v1.2.0", 86 | expected: 1, // latest, current -> upgrade! 87 | }, 88 | { 89 | name: "FirstNewer(minor)", 90 | first: "v1.2.3", 91 | second: "v1.1.3", 92 | expected: 1, // latest, current -> upgrade! 93 | }, 94 | { 95 | name: "FirstNewer(major)", 96 | first: "v2.1.3", 97 | second: "v1.2.3", 98 | expected: 1, // latest, current -> upgrade! 99 | }, 100 | { 101 | name: "FirstOlder(patch)", 102 | first: "v1.2.0", 103 | second: "v1.2.3", 104 | expected: -1, // latest, current -> no upgrade 105 | }, 106 | { 107 | name: "FirstOlder(minor)", 108 | first: "v1.1.3", 109 | second: "v1.2.3", 110 | expected: -1, // latest, current -> no upgrade 111 | }, 112 | { 113 | name: "FirstOlder(major)", 114 | first: "v1.2.3", 115 | second: "v2.1.3", 116 | expected: -1, // latest, current -> no upgrade 117 | }, 118 | { 119 | name: "BothNoSemver", 120 | first: "junk", 121 | second: "junk", 122 | expected: -1, // latest, current -> no upgrade 123 | }, 124 | { 125 | name: "BothNoSemverDifferent", 126 | first: "junk2", 127 | second: "junk1", 128 | expected: -1, // latest, current -> no upgrade 129 | }, 130 | { 131 | name: "FirstNoSemver", 132 | first: "junk", 133 | second: "v1.2.3", 134 | expected: -1, // latest, current -> no upgrade 135 | }, 136 | { 137 | name: "SecondNoSemver", 138 | first: "v1.2.3", 139 | second: "junk", 140 | expected: 1, // latest, current -> upgrade! 141 | }, 142 | } 143 | for _, tt := range tests { 144 | t.Run(tt.name, func(t *testing.T) { 145 | result := cmpTags(tt.first, tt.second) 146 | switch tt.expected { 147 | case 1: 148 | require.True(t, result > 0, "result should be positive") 149 | case -1: 150 | require.True(t, result < 0, "result should be negative") 151 | case 0: 152 | require.Equal(t, 0, result, "result should be zero") 153 | } 154 | }) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /gammacli-linux-install-v0.7.0.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This bash script downloads and installs a release pre-built gamma-cli 3 | # This script assumes you have Docker installed including elevated permissions for your 4 | # user to perform mundane docker tasks such as 'docker ps' (elevated = without the need for sudo) 5 | # Read more at: https://docs.docker.com/v17.12/install/linux/linux-postinstall/ 6 | # If you don't have Docker installed, please have a look here on how to install it on Ubuntu Linux: 7 | # https://docs.docker.com/v17.12/install/linux/docker-ce/ubuntu/ 8 | 9 | docker ps &> /dev/null 10 | 11 | DOCKER_TEST_EXITCODE=$? 12 | 13 | if [[ $DOCKER_TEST_EXITCODE != 0 ]]; then 14 | echo "Docker is not properly installed" 15 | echo "Read more here: https://docs.docker.com/v17.12/install/linux/linux-postinstall/" 16 | exit 1 17 | fi 18 | 19 | GAMMA_CLI_VERSION="v0.7.0" 20 | GAMMA_CLI_URL="https://github.com/orbs-network/gamma-cli/releases/download/$GAMMA_CLI_VERSION/gammacli-linux-x86-64-$GAMMA_CLI_VERSION.tar.gz" 21 | 22 | echo "Downloading pre-built gamma-cli ($GAMMA_CLI_VERSION) from it's official GitHub release repository.." 23 | wget $GAMMA_CLI_URL 24 | tar -zxvf gammacli*.tar.gz 25 | sudo mv _bin/gamma-cli /usr/bin/gamma-cli 26 | 27 | echo "gamma-cli successfully installed" 28 | 29 | exit 0 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/orbs-network/gamma-cli 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/orbs-network/crypto-lib-go v1.2.0 7 | github.com/orbs-network/lean-helix-go v0.2.7 8 | github.com/orbs-network/orbs-client-sdk-go v0.18.0 9 | github.com/orbs-network/orbs-spec v0.0.0-20200312223140-a78d945bab99 10 | github.com/pkg/errors v0.8.1 11 | github.com/stretchr/testify v1.4.0 12 | ) 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= 5 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 6 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 7 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 8 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 9 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 10 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 11 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 12 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 13 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 14 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 15 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 16 | github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 17 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 18 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 19 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 20 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 21 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 22 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 23 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 24 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 25 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 26 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 27 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 28 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 29 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 30 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 31 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 32 | github.com/ethereum/go-ethereum v1.9.6/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= 33 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 34 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 35 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 36 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 37 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 38 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 39 | github.com/go-playground/ansi v2.1.0+incompatible h1:f9ldskdk1seTFmYjbmPaYB+WYsDKWc4UXcGb+e9JrN8= 40 | github.com/go-playground/ansi v2.1.0+incompatible/go.mod h1:OCdnfTFO/GfFtp+ktUt+PhElbGOwyTRUuRUsA+Y5pSU= 41 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 42 | github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= 43 | github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= 44 | github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= 45 | github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= 46 | github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= 47 | github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= 48 | github.com/gobuffalo/packr/v2 v2.5.2/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= 49 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 50 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 51 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 52 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 53 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 54 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 55 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 56 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 57 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 58 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 59 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 60 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 61 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 62 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 63 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 64 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 65 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 66 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 67 | github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 68 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 69 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 70 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 71 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 72 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 73 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 74 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 75 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 76 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 77 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 78 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 79 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 80 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 81 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 82 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 83 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 84 | github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 85 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 86 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 87 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 88 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 89 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 90 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 91 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 92 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 93 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 94 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 95 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 96 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 97 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 98 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 99 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 100 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 101 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 102 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 103 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 104 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 105 | github.com/orbs-network/crypto-lib-go v1.2.0 h1:ZB+RCD8dPE2di97J5ap/7VX+7yuNNyey5P9p2nSHhvA= 106 | github.com/orbs-network/crypto-lib-go v1.2.0/go.mod h1:2jw6UQyT53aRh425j7mpxaGDhvfGVCfTqqBj22zULOs= 107 | github.com/orbs-network/go-mock v0.0.0-20180813130752-890a1ee8d0a1/go.mod h1:Hfj5NDPp07PIkGv5y8g1C0zsMXbrVTPQVIvSuHSHyvo= 108 | github.com/orbs-network/gojay v1.3.0 h1:TDqmmbgwHum9oXq1iexd+J+IUBm4/gtlyoOP5HV8rvw= 109 | github.com/orbs-network/gojay v1.3.0/go.mod h1:xdSp1mz0+DL+c6OLsbZ5qB/Gtygikcr5NdSsU1GsRC0= 110 | github.com/orbs-network/govnr v0.2.0 h1:Txazgo4Jd29hiARXg6nMqK2pmJA85KeXR+ZjLNy9WZc= 111 | github.com/orbs-network/govnr v0.2.0/go.mod h1:kZctUOFclDbO3Z6w559++l4qh0FPb57XdE5IdOFCbI4= 112 | github.com/orbs-network/lean-helix-go v0.2.3 h1:MwuN27C+y+WsvWcgwXoe0Gvi9p9qNR+a9LvLF7eERXk= 113 | github.com/orbs-network/lean-helix-go v0.2.3/go.mod h1:CYJzVWQROmK7DZGW0cFpNFbqLc8RdwIc8+n8uk3+KbM= 114 | github.com/orbs-network/lean-helix-go v0.2.7 h1:d7k67YUIMqXihIl5x/S9p7VIpBGpBzI1D/xR1x2Y/Ro= 115 | github.com/orbs-network/lean-helix-go v0.2.7/go.mod h1:9E/1sZEMZvNLHrP+nif36bio2zKbCkueji4R9e7vJnI= 116 | github.com/orbs-network/membuffers v0.3.0/go.mod h1:b6+sJ9+pgca7HHle0e85RDd5zL0Hv360Xec7TGVrGFk= 117 | github.com/orbs-network/membuffers v0.3.2 h1:dpUJXBTjvFkNputqIjCfBJnAJszZALtfuWcf9hGvg/4= 118 | github.com/orbs-network/membuffers v0.3.2/go.mod h1:M5ABv0m0XBGoJbX+7UKVY02hLF4XhS2SlZVEVABMc6M= 119 | github.com/orbs-network/membuffers v0.4.0 h1:tqeCLjdXJX3JIGy2mEMroeE+vG5mWTZx1vpwz7sgQKc= 120 | github.com/orbs-network/membuffers v0.4.0/go.mod h1:mhOIfhkMQWKhbQbwD2BoIlV9eAA3LwZXMC0+JIrDmCM= 121 | github.com/orbs-network/orbs-client-sdk-go v0.9.0 h1:tl0wxD8gSCXGO1moMMznqs6RDtHOSD2EbPzWAu++X94= 122 | github.com/orbs-network/orbs-client-sdk-go v0.9.0/go.mod h1:G2CJh+3UoKD1S2Z7Kzdt5cAh+kTinKFHLyGeOEUj1sA= 123 | github.com/orbs-network/orbs-client-sdk-go v0.13.0 h1:RoZ/wyQbnQhr1Pa06k3qFBSMegvlkI/uwXOhGib97Po= 124 | github.com/orbs-network/orbs-client-sdk-go v0.13.0/go.mod h1:1KsIoX5oZrLRwi96bF6k0Dy9dZaym2H88hCDi92R2YM= 125 | github.com/orbs-network/orbs-client-sdk-go v0.18.0 h1:xR/cais6t7SEU7D7GVmGv5rOMQozB0WkUQlKHTcn0Jg= 126 | github.com/orbs-network/orbs-client-sdk-go v0.18.0/go.mod h1:t7iiF0hkB3Grnbsu4yJ05SRsoEmO/fRfqCJK2egNvQ4= 127 | github.com/orbs-network/orbs-contract-sdk v1.0.0/go.mod h1:N+caPmVwyn3p+kgPwfb43bo4qAcRDoiaq/gw/ag1mHo= 128 | github.com/orbs-network/orbs-contract-sdk v1.4.0 h1:lbpo83A4cIQPzvyloVmNk/cVP6MO5BEn+zw0/Vg+OeI= 129 | github.com/orbs-network/orbs-contract-sdk v1.4.0/go.mod h1:N+caPmVwyn3p+kgPwfb43bo4qAcRDoiaq/gw/ag1mHo= 130 | github.com/orbs-network/orbs-spec v0.0.0-20190702065947-c6cfaf7cd01a/go.mod h1:9Bv/kJ/Q7cIlIYmlzsBHelseVJmyw2zywuW3TSvQX5g= 131 | github.com/orbs-network/orbs-spec v0.0.0-20191029121602-b5af15c91a90 h1:q4IQsP6nuxsDZ6WIurB6LjBzdEoUP0iBkffsFJNGTtI= 132 | github.com/orbs-network/orbs-spec v0.0.0-20191029121602-b5af15c91a90/go.mod h1:tun/2f3PycO5lhYQtISnbW3WgGhru1FhpECEg39Or+A= 133 | github.com/orbs-network/orbs-spec v0.0.0-20191114152037-24b26e24030e h1:2uhGT3x5lcuvdX7rkw1nKwPjzgA1bBQ3RzNkWSSPGP0= 134 | github.com/orbs-network/orbs-spec v0.0.0-20191114152037-24b26e24030e/go.mod h1:D4+jHMhQ+mPB4uhqZ2wtzuG8RV2JgltWG1FqAwLIaOw= 135 | github.com/orbs-network/orbs-spec v0.0.0-20200312223140-a78d945bab99 h1:SIM5FvYeayQfRWBTwuPfe/JHI1NrKY7QaTzjfemjAkA= 136 | github.com/orbs-network/orbs-spec v0.0.0-20200312223140-a78d945bab99/go.mod h1:D4+jHMhQ+mPB4uhqZ2wtzuG8RV2JgltWG1FqAwLIaOw= 137 | github.com/orbs-network/pbparser v0.2.0/go.mod h1:WSzcxgH5xzywQm0YSASbD7RcdxBXZgqZaDVK8M+8DJ8= 138 | github.com/orbs-network/pbparser v0.3.0/go.mod h1:WSzcxgH5xzywQm0YSASbD7RcdxBXZgqZaDVK8M+8DJ8= 139 | github.com/orbs-network/scribe v0.1.0 h1:Kn/EQpifQFae+F7HRIoTIipUsSHZNcfQ3HJOhD/b+8M= 140 | github.com/orbs-network/scribe v0.1.0/go.mod h1:FmGcbukz5eolO+mqzxwmuy4RF4UEoLfGJIeEDAoGsBU= 141 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 142 | github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= 143 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 144 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 145 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 146 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 147 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 148 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 149 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 150 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 151 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 152 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 153 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 154 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 155 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 156 | github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= 157 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 158 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 159 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 160 | github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= 161 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 162 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 163 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 164 | github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 165 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 166 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 167 | github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 168 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 169 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 170 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 171 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 172 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 173 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 174 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 175 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 176 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 177 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 178 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 179 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 180 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= 181 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 182 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 183 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 184 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 185 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 186 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 187 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 188 | github.com/tallstoat/pbparser v0.2.0/go.mod h1:aUC6W9uQLeAXZkknve8ZDO6InhRYpYHlJ9kvsQh1i2k= 189 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 190 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= 191 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 192 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 193 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 194 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 195 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 196 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 197 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 198 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 199 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 200 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 201 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 202 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 203 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 204 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 205 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 206 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 207 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 208 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 209 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= 210 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 211 | golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA= 212 | golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 213 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 214 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 215 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 216 | golang.org/x/exp v0.0.0-20190718202018-cfdd5522f6f6/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= 217 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 218 | golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 219 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 220 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 221 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 222 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 223 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 224 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 225 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 226 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 227 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 228 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 229 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 230 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 231 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 232 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 233 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 234 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 235 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 236 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 237 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 238 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 239 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 240 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 241 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 242 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 243 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 244 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 245 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 246 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 247 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 248 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 249 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 250 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 251 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 252 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 253 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 254 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 255 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 256 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 257 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 258 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 259 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 260 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 261 | golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 262 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 263 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 264 | golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 265 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 266 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 267 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 268 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 269 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 270 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 271 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 272 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 273 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 274 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 275 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 276 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 277 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 278 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 279 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 280 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 281 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 282 | golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 283 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 284 | golang.org/x/tools v0.0.0-20190723021737-8bb11ff117ca/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= 285 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 286 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 287 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 288 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 289 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 290 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 291 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 292 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 293 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 294 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 295 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 296 | google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 297 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 298 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 299 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 300 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 301 | google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 302 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 303 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 304 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 305 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 306 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 307 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 308 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 309 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 310 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 311 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 312 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 313 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 314 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 315 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 316 | -------------------------------------------------------------------------------- /help.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "flag" 11 | "fmt" 12 | "os" 13 | "reflect" 14 | "strings" 15 | ) 16 | 17 | func commandShowHelp(requiredOptions []string) { 18 | fmt.Fprintf(os.Stderr, "Usage:\n\n") 19 | fmt.Fprintf(os.Stderr, "gamma-cli COMMAND [OPTIONS]\n\n") 20 | 21 | fmt.Fprintf(os.Stderr, "Commands:\n\n") 22 | sortedCommands := sortCommands() 23 | for _, name := range sortedCommands { 24 | cmd := commands[name] 25 | fmt.Fprintf(os.Stderr, " %s %s %s\n", name, strings.Repeat(" ", 15-len(name)), cmd.desc) 26 | if cmd.args != "" { 27 | fmt.Fprintf(os.Stderr, " %s options: %s\n", strings.Repeat(" ", 15), cmd.args) 28 | } 29 | if cmd.example != "" { 30 | fmt.Fprintf(os.Stderr, " %s example: %s\n", strings.Repeat(" ", 15), cmd.example) 31 | } 32 | if cmd.example2 != "" { 33 | fmt.Fprintf(os.Stderr, " %s %s\n", strings.Repeat(" ", 15), cmd.example2) 34 | } 35 | fmt.Fprintf(os.Stderr, "\n") 36 | } 37 | fmt.Fprintf(os.Stderr, "\n") 38 | 39 | fmt.Fprintf(os.Stderr, "Options:\n\n") 40 | showOptions() 41 | fmt.Fprintf(os.Stderr, "\n") 42 | 43 | fmt.Fprintf(os.Stderr, "Multiple environments (eg. local and testnet) can be defined in orbs-gamma-config.json configuration file.\n") 44 | fmt.Fprintf(os.Stderr, "See https://orbs.gitbook.io for more info.\n") 45 | fmt.Fprintf(os.Stderr, "\n") 46 | 47 | os.Exit(2) 48 | } 49 | 50 | func commandVersion(requiredOptions []string) { 51 | log("gamma-cli version %s", GAMMA_CLI_VERSION) 52 | 53 | gammaVersion := verifyDockerInstalled(gammaHandlerOptions(), gammaHandlerOptions().dockerRegistryTagsUrl) 54 | log("Gamma server version %s (docker)", gammaVersion) 55 | 56 | prismVersion := verifyDockerInstalled(prismHandlerOptions(), prismHandlerOptions().dockerRegistryTagsUrl) 57 | log("Prism blockchain explorer version %s (docker)", prismVersion) 58 | } 59 | 60 | func sortCommands() []string { 61 | res := make([]string, len(commands)) 62 | for name, cmd := range commands { 63 | res[cmd.sort] = name 64 | } 65 | return res 66 | } 67 | 68 | // taken from package flag (func PrintDefaults) 69 | func showOptions() { 70 | flag.VisitAll(func(f *flag.Flag) { 71 | // ignore list 72 | if strings.HasPrefix(f.Name, "arg") { 73 | return 74 | } 75 | 76 | s := fmt.Sprintf(" -%s", f.Name) 77 | name, usage := flag.UnquoteUsage(f) 78 | if len(name) > 0 { 79 | s += " " + name 80 | } 81 | if len(s) <= 4 { 82 | s += "\t" 83 | } else { 84 | s += "\n \t" 85 | } 86 | s += strings.Replace(usage, "\n", "\n \t", -1) 87 | 88 | if !isZeroValue(f, f.DefValue) { 89 | s += fmt.Sprintf(" (default %q)", f.DefValue) 90 | } 91 | fmt.Fprint(os.Stderr, s, "\n") 92 | }) 93 | } 94 | 95 | // taken from package flag 96 | func isZeroValue(f *flag.Flag, value string) bool { 97 | typ := reflect.TypeOf(f.Value) 98 | var z reflect.Value 99 | if typ.Kind() == reflect.Ptr { 100 | z = reflect.New(typ.Elem()) 101 | } else { 102 | z = reflect.Zero(typ) 103 | } 104 | if value == z.Interface().(flag.Value).String() { 105 | return true 106 | } 107 | switch value { 108 | case "false", "", "0": 109 | return true 110 | } 111 | return false 112 | } 113 | -------------------------------------------------------------------------------- /is_ready.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "net" 12 | "time" 13 | ) 14 | 15 | const IS_READY_TOTAL_WAIT_TIMEOUT = 20 * time.Second 16 | const IS_READY_POLLING_INTERVAL = 500 * time.Millisecond 17 | 18 | const DEPLOY_GET_INFO_SYSTEM_METHOD_NAME = "getInfo" 19 | 20 | func isDockerReadyAndListening() bool { 21 | signer := getTestKeyFromFile(*flagSigner) 22 | 23 | client := createOrbsClient() 24 | payload, err := client.CreateQuery(signer.PublicKey, DEPLOY_SYSTEM_CONTRACT_NAME, DEPLOY_GET_INFO_SYSTEM_METHOD_NAME, DEPLOY_SYSTEM_CONTRACT_NAME) 25 | if err != nil { 26 | die("Could not encode payload of the message about to be sent to server.\n\n%s", err.Error()) 27 | } 28 | 29 | response, err := client.SendQuery(payload) 30 | if err != nil { 31 | return false 32 | } 33 | 34 | // the system will not accept new transactions before block 1 is closed under consensus 35 | if response.BlockHeight == 0 { 36 | return false 37 | } 38 | 39 | return true 40 | } 41 | 42 | func waitUntilDockerIsReadyAndListening(timeout time.Duration) { 43 | start := time.Now() 44 | for time.Now().Sub(start) < timeout { 45 | if isDockerReadyAndListening() { 46 | return 47 | } 48 | time.Sleep(IS_READY_POLLING_INTERVAL) 49 | } 50 | } 51 | 52 | func isPortListening(port int) bool { 53 | server, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 54 | if err != nil { 55 | return true // if it fails then the port is likely taken 56 | } 57 | server.Close() 58 | return false 59 | } 60 | -------------------------------------------------------------------------------- /jsoncodec/args.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "encoding/hex" 11 | "github.com/orbs-network/crypto-lib-go/crypto/encoding" 12 | "github.com/pkg/errors" 13 | "math/big" 14 | "reflect" 15 | "strconv" 16 | "strings" 17 | ) 18 | 19 | const supported = "Supported types are: uint32 uint64 uint256 bool string bytes bytes20 bytes32 uint32Array uint64Array uint256Array boolArray stringArray bytesArray bytes20Array bytes32Array gamma:address gamma:keys-file-address" 20 | 21 | type Arg struct { 22 | Type string 23 | Value interface{} 24 | } 25 | 26 | func isArgsInputStructureValid(args []*Arg) error { 27 | for i, arg := range args { 28 | rValue := reflect.TypeOf(arg.Value).String() 29 | if strings.HasSuffix(arg.Type, "Array") { 30 | if rValue != "[]interface {}" { 31 | return errors.Errorf("Argument %d's Type is marked as an Array and it's Value should contain an array of string\nCurrently %s\n", i+1, rValue) 32 | } 33 | } else if rValue != "string" { 34 | return errors.Errorf("Argument %d's Type is marked as a Scalar and it's Value should contain a string", i+1) 35 | } 36 | } 37 | return nil 38 | } 39 | 40 | func unmarshalScalar(argType, value string) (interface{}, error) { 41 | switch argType { 42 | case "uint32": 43 | val, err := strconv.ParseUint(value, 10, 32) 44 | if err != nil { 45 | return nil, errors.Errorf("a numeric value\nCurrent value: '%s'", value) 46 | } 47 | return uint32(val), nil 48 | case "uint64": 49 | val, err := strconv.ParseUint(value, 10, 64) 50 | if err != nil { 51 | return nil, errors.Errorf("a numeric value\nCurrent value: '%s'", value) 52 | } 53 | return val, nil 54 | case "string": 55 | return value, nil 56 | case "bytes": 57 | val, err := simpleDecodeHex(value) 58 | if err != nil { 59 | return nil, errors.Errorf("bytes in hex format\nHex decoder returned error: %s\nCurrent value: '%s'", err.Error(), value) 60 | } 61 | return val, nil 62 | case "bool": 63 | if value == "1" { 64 | return true, nil 65 | } else if value == "0" { 66 | return false, nil 67 | } else { 68 | return nil, errors.Errorf("1 or 0\nCurrent value: '%s'", value) 69 | } 70 | case "uint256": 71 | valBytes, err := simpleDecodeHex(value) 72 | if err != nil { 73 | return nil, errors.Errorf("uint256 value in bytes in a hex format (64 hexes)\nHex decoder returned error: %s\nCurrent value: '%s'", err.Error(), value) 74 | } 75 | if len(valBytes) != 32 { 76 | return nil, errors.Errorf("uint256 value in bytes in a hex format (64 hexes)\n Actual size : %d", len(valBytes)) 77 | } 78 | val := big.NewInt(0) 79 | val.SetBytes(valBytes) 80 | return val, nil 81 | case "bytes20": 82 | valBytes, err := simpleDecodeHex(value) 83 | if err != nil { 84 | return nil, errors.Errorf("bytes20 in a hex format (40 hexes)\nHex decoder returned error: %s\nCurrent value: '%s'", err.Error(), value) 85 | } 86 | if len(valBytes) != 20 { 87 | return nil, errors.Errorf("bytes20 in a hex format (40 hexes)\n Actual size : %d", len(valBytes)) 88 | } 89 | var val [20]byte 90 | copy(val[:], valBytes) 91 | return val, nil 92 | case "bytes32": 93 | valBytes, err := simpleDecodeHex(value) 94 | if err != nil { 95 | return nil, errors.Errorf("bytes32 in a hex format (64 hexes)\nHex decoder returned error: %s\nCurrent value: '%s'", err.Error(), value) 96 | } 97 | if len(valBytes) != 32 { 98 | return nil, errors.Errorf("bytes32 in a hex format (64 hexes)\n Actual size : %d", len(valBytes)) 99 | } 100 | var val [32]byte 101 | copy(val[:], valBytes) 102 | return val, nil 103 | default: 104 | return nil, errors.Errorf("a known type. '%s' is unsupported\n%s", argType, supported) 105 | } 106 | } 107 | 108 | func unmarshalArray(argType string, argValues []interface{}) (interface{}, error) { 109 | switch argType { 110 | case "uint32Array": 111 | var argArrayRes []uint32 112 | for j, argValue := range argValues { 113 | val, err := strconv.ParseUint(argValue.(string), 10, 32) 114 | if err != nil { 115 | return nil, errors.Errorf("element %d should be a string containing a numeric value\nCurrent value: '%s'", j+1, argValue) 116 | } 117 | argArrayRes = append(argArrayRes, uint32(val)) 118 | } 119 | return argArrayRes, nil 120 | case "uint64Array": 121 | var argArrayRes []uint64 122 | for j, argValue := range argValues { 123 | val, err := strconv.ParseUint(argValue.(string), 10, 64) 124 | if err != nil { 125 | return nil, errors.Errorf("element %d should be a string containing a numeric value\nCurrent value: '%s'", j+1, argValue) 126 | } 127 | argArrayRes = append(argArrayRes, val) 128 | } 129 | return argArrayRes, nil 130 | case "stringArray": 131 | var argArrayRes []string 132 | for _, argValue := range argValues { 133 | argArrayRes = append(argArrayRes, argValue.(string)) 134 | } 135 | return argArrayRes, nil 136 | case "bytesArray": 137 | var argArrayRes [][]byte 138 | for j, argValue := range argValues { 139 | val, err := simpleDecodeHex(argValue.(string)) 140 | if err != nil { 141 | return nil, errors.Errorf("element %d should be a string containing bytes in hex format\nHex decoder returned error: %s\nCurrent value: '%s'", j+1, err.Error(), argValue) 142 | } 143 | argArrayRes = append(argArrayRes, val) 144 | } 145 | return argArrayRes, nil 146 | case "boolArray": 147 | var argArrayRes []bool 148 | for j, argValue := range argValues { 149 | s := argValue.(string) 150 | if s == "1" { 151 | argArrayRes = append(argArrayRes, true) 152 | } else if s == "0" { 153 | argArrayRes = append(argArrayRes, false) 154 | } else { 155 | return nil, errors.Errorf("element %d should be a string containing 1 or 0\nCurrent value: '%s'", j+1, argValue) 156 | } 157 | } 158 | return argArrayRes, nil 159 | case "uint256Array": 160 | var argArrayRes []*big.Int 161 | for j, argValue := range argValues { 162 | valBytes, err := simpleDecodeHex(argValue.(string)) 163 | if err != nil { 164 | return nil, errors.Errorf("element %d should be a string containing uint256 in hex format (64 hexes)\nHex decoder returned error: %s\nCurrent value: '%s'", j+1, err.Error(), argValue) 165 | } 166 | if len(valBytes) != 32 { 167 | return nil, errors.Errorf("element %d should be a string containing uint256 in a hex format (64 hexes)\n Actual size : %d", j+1, len(valBytes)) 168 | } 169 | val := big.NewInt(0) 170 | val.SetBytes(valBytes) 171 | argArrayRes = append(argArrayRes, val) 172 | } 173 | return argArrayRes, nil 174 | case "bytes20Array": 175 | var argArrayRes [][20]byte 176 | for j, argValue := range argValues { 177 | valBytes, err := simpleDecodeHex(argValue.(string)) 178 | if err != nil { 179 | return nil, errors.Errorf("element %d should be a string containing bytes20 in hex format (40 hexes)\nHex decoder returned error: %s\nCurrent value: '%s'", j+1, err.Error(), argValue) 180 | } 181 | if len(valBytes) != 20 { 182 | return nil, errors.Errorf("element %d should be a string containing bytes20 in a hex format (40 hexes)\n Actual size : %d", j+1, len(valBytes)) 183 | } 184 | var val [20]byte 185 | copy(val[:], valBytes) 186 | argArrayRes = append(argArrayRes, val) 187 | } 188 | return argArrayRes, nil 189 | case "bytes32Array": 190 | var argArrayRes [][32]byte 191 | for j, argValue := range argValues { 192 | valBytes, err := simpleDecodeHex(argValue.(string)) 193 | if err != nil { 194 | return nil, errors.Errorf("element %d should be a string containing bytes32 in hex format (64 hexes)\nHex decoder returned error: %s\nCurrent value: '%s'", j+1, err.Error(), argValue) 195 | } 196 | if len(valBytes) != 32 { 197 | return nil, errors.Errorf("element %d should be a string containing bytes32 in a hex format (64 hexes)\n Actual size : %d", j+1, len(valBytes)) 198 | } 199 | var val [32]byte 200 | copy(val[:], valBytes) 201 | argArrayRes = append(argArrayRes, val) 202 | } 203 | return argArrayRes, nil 204 | default: 205 | return nil, errors.Errorf("a known type. '%s' is unsupported\n%s", argType, supported) 206 | } 207 | } 208 | 209 | func UnmarshalArgs(args []*Arg, getTestKeyFromFile func(string) *RawKey) ([]interface{}, error) { 210 | if err := isArgsInputStructureValid(args); err != nil { 211 | return nil, err 212 | } 213 | var res []interface{} 214 | for i, arg := range args { 215 | if arg.Type == "gamma:address" { 216 | val, err := encoding.DecodeHex(arg.Value.(string)) 217 | if err != nil { 218 | return nil, errors.Errorf("Value of argument %d should be a string containing the bytes in hex\nHex decoder returned error: %s\n\nCurrent value: '%s'", i+1, err.Error(), arg.Value) 219 | } 220 | res = append(res, val) 221 | } else if arg.Type == "gamma:keys-file-address" { 222 | key := getTestKeyFromFile(arg.Value.(string)) 223 | res = append(res, key.Address) 224 | } else if strings.HasSuffix(arg.Type, "Array") { 225 | valArray, err := unmarshalArray(arg.Type, arg.Value.([]interface{})) 226 | if err != nil { 227 | return nil, errors.Errorf("Value of array argument %d, %s", i+1, err.Error()) 228 | } 229 | res = append(res, valArray) 230 | } else { 231 | val, err := unmarshalScalar(arg.Type, arg.Value.(string)) 232 | if err != nil { 233 | return nil, errors.Errorf("Value of argument %d should be a string containing %s", i+1, err.Error()) 234 | } 235 | res = append(res, val) 236 | } 237 | } 238 | return res, nil 239 | } 240 | 241 | func MarshalArgs(arguments []interface{}) ([]*Arg, error) { 242 | var res []*Arg 243 | for i, arg := range arguments { 244 | if reflect.TypeOf(arg).Kind() == reflect.Slice { // all []Type including []byte 245 | var arrArguments []string 246 | switch arg := arg.(type) { 247 | case []byte: 248 | res = append(res, &Arg{"bytes", "0x" + hex.EncodeToString(arg)}) 249 | case []uint32: 250 | for _, v := range arg { 251 | arrArguments = append(arrArguments, strconv.FormatUint(uint64(v), 10)) 252 | } 253 | res = append(res, &Arg{"uint32Array", arrArguments}) 254 | case []uint64: 255 | for _, v := range arg { 256 | arrArguments = append(arrArguments, strconv.FormatUint(v, 10)) 257 | } 258 | res = append(res, &Arg{"uint64Array", arrArguments}) 259 | case []string: 260 | res = append(res, &Arg{"stringArray", arg}) 261 | case [][]byte: 262 | for _, v := range arg { 263 | arrArguments = append(arrArguments, "0x"+hex.EncodeToString(v)) 264 | } 265 | res = append(res, &Arg{"bytesArray", arrArguments}) 266 | case []bool: 267 | for _, v := range arg { 268 | if v { 269 | arrArguments = append(arrArguments, "1") 270 | } else { 271 | arrArguments = append(arrArguments, "0") 272 | } 273 | } 274 | res = append(res, &Arg{"boolArray", arrArguments}) 275 | case []*big.Int: 276 | val := [32]byte{} 277 | for _, v := range arg { 278 | b := v.Bytes() 279 | copy(val[32-len(b):], b) 280 | arrArguments = append(arrArguments, "0x"+hex.EncodeToString(val[:])) 281 | } 282 | res = append(res, &Arg{"uint256Array", arrArguments}) 283 | case [][20]byte: 284 | for _, v := range arg { 285 | arrArguments = append(arrArguments, "0x"+hex.EncodeToString(v[:])) 286 | } 287 | res = append(res, &Arg{"bytes20Array", arrArguments}) 288 | case [][32]byte: 289 | for _, v := range arg { 290 | arrArguments = append(arrArguments, "0x"+hex.EncodeToString(v[:])) 291 | } 292 | res = append(res, &Arg{"bytes32Array", arrArguments}) 293 | default: 294 | return nil, errors.Errorf("Type of argument %d '%T' is unsupported\n\n%s", i+1, arg, supported) 295 | } 296 | } else { 297 | switch arg := arg.(type) { 298 | case uint32: 299 | res = append(res, &Arg{"uint32", strconv.FormatUint(uint64(arg), 10)}) 300 | case uint64: 301 | res = append(res, &Arg{"uint64", strconv.FormatUint(arg, 10)}) 302 | case string: 303 | res = append(res, &Arg{"string", arg}) 304 | case bool: 305 | if arg { 306 | res = append(res, &Arg{"bool", "1"}) 307 | } else { 308 | res = append(res, &Arg{"bool", "0"}) 309 | } 310 | case *big.Int: 311 | val := [32]byte{} 312 | b := arg.Bytes() 313 | copy(val[32-len(b):], b) 314 | res = append(res, &Arg{"uint256", "0x" + hex.EncodeToString(val[:])}) 315 | case [20]byte: 316 | res = append(res, &Arg{"bytes20", "0x" + hex.EncodeToString(arg[:])}) 317 | case [32]byte: 318 | res = append(res, &Arg{"bytes32", "0x" + hex.EncodeToString(arg[:])}) 319 | default: 320 | return nil, errors.Errorf("Type of argument %d '%T' is unsupported\n\n%s", i+1, arg, supported) 321 | } 322 | } 323 | } 324 | return res, nil 325 | } 326 | 327 | func simpleDecodeHex(value string) ([]byte, error) { 328 | if strings.HasPrefix(value, "0x") { 329 | value = value[2:] 330 | } 331 | return hex.DecodeString(value) 332 | } 333 | -------------------------------------------------------------------------------- /jsoncodec/args_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "github.com/stretchr/testify/require" 11 | "math/big" 12 | "testing" 13 | ) 14 | 15 | func TestArgumentsUnMarshalingTypes_InputCorrectlyStructured(t *testing.T) { 16 | expectedBigInt := big.NewInt(0) 17 | expectedBigInt.SetBytes([]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}) 18 | 19 | tests := []struct { 20 | name string 21 | shouldErr bool 22 | arg *Arg 23 | native interface{} 24 | }{ 25 | {"uint32", false, &Arg{"uint32", "19480514"}, uint32(19480514)}, 26 | {"uint32-fail", true, &Arg{"uint32", "bad text"}, uint32(0)}, 27 | {"uint64", false, &Arg{"uint64", "19480514000000000"}, uint64(19480514000000000)}, 28 | {"uint64-fail", true, &Arg{"uint64", "bad text"}, uint64(0)}, 29 | {"string", false, &Arg{"string", "hello my name is ?"}, "hello my name is ?"}, 30 | {"bytes", false, &Arg{"bytes", "ffee00eeff"}, []byte{0xff, 0xee, 0x00, 0xee, 0xff}}, 31 | {"bytes-fail", true, &Arg{"bytes", "yyyy"}, []byte{}}, 32 | {"bytes", false, &Arg{"bytes", "ffee00eeff"}, []byte{0xff, 0xee, 0x00, 0xee, 0xff}}, 33 | {"bool-false", false, &Arg{"bool", "0"}, false}, 34 | {"bool-fail", true, &Arg{"bool", "2"}, false}, 35 | {"bytes20", false, &Arg{"bytes20", "0011223344556677889900112233445566778899"}, [20]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}}, 36 | {"bytes20-fail", true, &Arg{"bytes20", "yyyy"}, [20]byte{}}, 37 | {"bytes20-fail-size", true, &Arg{"bytes20", "00112233445566778899001122334455667788"}, [20]byte{}}, 38 | {"bytes32", false, &Arg{"bytes32", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}, [32]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}, 39 | {"bytes32-fail", true, &Arg{"bytes32", "yyyy"}, [32]byte{}}, 40 | {"bytes32-fail-size", true, &Arg{"bytes32", "00112233445566778899aabbccddeeff001122334455667788"}, [32]byte{}}, 41 | {"bigint", false, &Arg{"uint256", "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}, expectedBigInt}, 42 | {"bigint-fail", true, &Arg{"uint256", "yyyy"}, nil}, 43 | {"bigint-fail-size", true, &Arg{"uint256", "00112233445566778899aabbccddeeff001122334455667788"}, nil}, 44 | {"unknown type string", true, &Arg{"uint8", "19480514"}, uint32(0)}, 45 | // not checking internal translation of single array value as it is done by same function internally 46 | {"uint32Array", false, &Arg{"uint32Array", []interface{}{"19480514", "1"}}, []uint32{uint32(19480514), uint32(1)}}, 47 | {"uint64Array", false, &Arg{"uint64Array", []interface{}{"19480514000000000", "1"}}, []uint64{uint64(19480514000000000), uint64(1)}}, 48 | {"stringArray", false, &Arg{"stringArray", []interface{}{"hello my name is ?", "what?", "who"}}, []string{"hello my name is ?", "what?", "who"}}, 49 | {"bytesArray", false, &Arg{"bytesArray", []interface{}{"ffee00eeff", "00001122"}}, [][]byte{{0xff, 0xee, 0x00, 0xee, 0xff}, {0x00, 0x00, 0x11, 0x22}}}, 50 | {"boolArray", false, &Arg{"boolArray", []interface{}{"0", "1", "1", "1"}}, []bool{false, true, true, true}}, 51 | {"bytes20Array", false, &Arg{"bytes20Array", []interface{}{"0011223344556677889900112233445566778899"}}, [][20]byte{{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}}}, 52 | {"bytes32Array", false, &Arg{"bytes32Array", []interface{}{"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}}, [][32]byte{{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}}, 53 | {"bigintArray", false, &Arg{"uint256Array", []interface{}{"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}}, []*big.Int{expectedBigInt}}, 54 | {"unknown type Array", true, &Arg{"uint8Array", []interface{}{"19480514"}}, uint32(0)}, 55 | } 56 | 57 | for _, cTest := range tests { 58 | argList := []*Arg{cTest.arg} 59 | nativeList := []interface{}{cTest.native} 60 | 61 | resNativeList, err := UnmarshalArgs(argList, func(string) *RawKey { return nil }) 62 | if cTest.shouldErr { 63 | require.Error(t, err, "unmarshal %s should fail", cTest.name) 64 | } else { 65 | require.NoError(t, err, "unmarshal %s should not fail", cTest.name) 66 | require.EqualValues(t, nativeList, resNativeList) 67 | } 68 | } 69 | } 70 | 71 | func TestArgumentsUnMarshalingTypes_IncorrectInputStructure(t *testing.T) { 72 | tests := []struct { 73 | name string 74 | arg *Arg 75 | }{ 76 | {"non-array-type with array-input", &Arg{"uint32", []string{"19480514"}}}, 77 | {"array-type with non-array-input", &Arg{"uint32Array", "19480514"}}, 78 | {"non-array-input is not string", &Arg{"uint64", 19480514000000000}}, 79 | {"array input is not string array", &Arg{"uint64Array", []uint32{10, 20}}}, 80 | } 81 | 82 | for _, cTest := range tests { 83 | argList := []*Arg{cTest.arg} 84 | 85 | _, err := UnmarshalArgs(argList, func(string) *RawKey { return nil }) 86 | require.Error(t, err, "unmarshal %s should fail", cTest.name) 87 | } 88 | } 89 | 90 | func TestArgumentsMarshaling_GoodFlow(t *testing.T) { 91 | aBigInt := big.NewInt(0) 92 | aBigInt.SetBytes([]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}) 93 | 94 | tests := []struct { 95 | name string 96 | arg *Arg 97 | native interface{} 98 | }{ 99 | {"uint32", &Arg{"uint32", "19480514"}, uint32(19480514)}, 100 | {"uint64", &Arg{"uint64", "19480514000000000"}, uint64(19480514000000000)}, 101 | {"string", &Arg{"string", "hello my name is ?"}, "hello my name is ?"}, 102 | {"bytes", &Arg{"bytes", "0xffee00eeff"}, []byte{0xff, 0xee, 0x00, 0xee, 0xff}}, 103 | {"bool-true", &Arg{"bool", "1"}, true}, 104 | {"bool-false", &Arg{"bool", "0"}, false}, 105 | {"bytes20", &Arg{"bytes20", "0x0011223344556677889900112233445566778899"}, [20]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}}, 106 | {"bytes32", &Arg{"bytes32", "0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}, [32]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}, 107 | {"bigint", &Arg{"uint256", "0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}, aBigInt}, 108 | {"uint32Array", &Arg{"uint32Array", []string{"19480514", "1"}}, []uint32{19480514, 1}}, 109 | {"uint64Array", &Arg{"uint64Array", []string{"19480514000000000", "1"}}, []uint64{19480514000000000, 1}}, 110 | {"stringArray", &Arg{"stringArray", []string{"hello", "my", "name"}}, []string{"hello", "my", "name"}}, 111 | {"bytesArray", &Arg{"bytesArray", []string{"0xffee00eeff", "0xffee00eeff"}}, [][]byte{{0xff, 0xee, 0x00, 0xee, 0xff}, {0xff, 0xee, 0x00, 0xee, 0xff}}}, 112 | {"boolArray", &Arg{"boolArray", []string{"1", "1", "0"}}, []bool{true, true, false}}, 113 | {"uint256Array", &Arg{"uint256Array", []string{"0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"}}, []*big.Int{aBigInt}}, 114 | {"bytes20Array", &Arg{"bytes20Array", []string{"0x0011223344556677889900112233445566778899", "0xaa112233445566778899001122334455667788ff"}}, [][20]byte{{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, {0xaa, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xff}}}, 115 | {"bytes32Array", &Arg{"bytes32Array", []string{"0x00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff", "0xaa112233445566778899aabbccddeeff00112233445566778899aabbccddee11"}}, [][32]byte{{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, {0xaa, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x11}}}, 116 | } 117 | 118 | for _, cTest := range tests { 119 | argList := []*Arg{cTest.arg} 120 | nativeList := []interface{}{cTest.native} 121 | 122 | resArgList, err := MarshalArgs(nativeList) 123 | require.NoError(t, err, "unmarshal %s should not fail", cTest.name) 124 | require.EqualValues(t, argList, resArgList) 125 | } 126 | } 127 | 128 | func TestArgumentsMarshaling_BadFlow(t *testing.T) { 129 | nativeList := []interface{}{1.0} 130 | _, err := MarshalArgs(nativeList) 131 | require.Error(t, err, "unmarshal %s should fail") 132 | } 133 | -------------------------------------------------------------------------------- /jsoncodec/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import "encoding/json" 10 | 11 | type ConfFile struct { 12 | Environments map[string]*ConfEnv 13 | } 14 | 15 | type ConfEnv struct { 16 | VirtualChain uint32 17 | Endpoints []string 18 | Experimental bool 19 | } 20 | 21 | func UnmarshalConfFile(bytes []byte) (*ConfFile, error) { 22 | var confFile *ConfFile 23 | err := json.Unmarshal(bytes, &confFile) 24 | return confFile, err 25 | } 26 | -------------------------------------------------------------------------------- /jsoncodec/events.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "github.com/orbs-network/orbs-client-sdk-go/codec" 11 | "github.com/pkg/errors" 12 | ) 13 | 14 | type Event struct { 15 | ContractName string 16 | EventName string 17 | Arguments []*Arg 18 | } 19 | 20 | func MarshalEvents(events []*codec.Event) ([]*Event, error) { 21 | res := []*Event{} 22 | for i, event := range events { 23 | eventArgs, err := MarshalArgs(event.Arguments) 24 | if err != nil { 25 | return nil, errors.Errorf("Event %d arguments marshaling failed with %s \n", i+1, err.Error()) 26 | } 27 | res = append(res, &Event{ 28 | ContractName: event.ContractName, 29 | EventName: event.EventName, 30 | Arguments: eventArgs, 31 | }) 32 | } 33 | return res, nil 34 | } 35 | -------------------------------------------------------------------------------- /jsoncodec/keys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import "encoding/json" 10 | 11 | type Key struct { 12 | PrivateKey string // hex string starting with 0x 13 | PublicKey string // hex string starting with 0x 14 | Address string // hex string starting with 0x 15 | } 16 | 17 | type RawKey struct { 18 | PrivateKey []byte 19 | PublicKey []byte 20 | Address []byte 21 | } 22 | 23 | func UnmarshalKeys(bytes []byte) (map[string]*Key, error) { 24 | keys := make(map[string]*Key) 25 | err := json.Unmarshal(bytes, &keys) 26 | return keys, err 27 | } 28 | 29 | func MarshalKeys(keys map[string]*Key) ([]byte, error) { 30 | return json.MarshalIndent(keys, "", " ") 31 | } 32 | -------------------------------------------------------------------------------- /jsoncodec/read.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "encoding/json" 11 | "github.com/orbs-network/orbs-client-sdk-go/codec" 12 | "github.com/pkg/errors" 13 | "strconv" 14 | ) 15 | 16 | type Read struct { 17 | ContractName string 18 | MethodName string 19 | Arguments []*Arg 20 | } 21 | 22 | func UnmarshalRead(bytes []byte) (*Read, error) { 23 | var read *Read 24 | err := json.Unmarshal(bytes, &read) 25 | return read, err 26 | } 27 | 28 | func MarshalReadResponse(r *codec.RunQueryResponse) ([]byte, error) { 29 | outputArgs, err := MarshalArgs(r.OutputArguments) 30 | if err != nil { 31 | return nil, errors.Errorf("Read response marshaling output arguments failed with %s \n", err.Error()) 32 | } 33 | outputEvents, err := MarshalEvents(r.OutputEvents) 34 | if err != nil { 35 | return nil, errors.Errorf("Read response marshaling output events failed with %s \n", err.Error()) 36 | } 37 | return json.MarshalIndent(&struct { 38 | RequestStatus codec.RequestStatus 39 | ExecutionResult codec.ExecutionResult 40 | OutputArguments []*Arg 41 | OutputEvents []*Event 42 | BlockHeight string 43 | BlockTimestamp string 44 | }{ 45 | RequestStatus: r.RequestStatus, 46 | ExecutionResult: r.ExecutionResult, 47 | OutputArguments: outputArgs, 48 | OutputEvents: outputEvents, 49 | BlockHeight: strconv.FormatUint(r.BlockHeight, 10), 50 | BlockTimestamp: r.BlockTimestamp.UTC().Format(codec.ISO_DATE_FORMAT), 51 | }, "", " ") 52 | } 53 | -------------------------------------------------------------------------------- /jsoncodec/send_tx.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "encoding/json" 11 | "github.com/orbs-network/orbs-client-sdk-go/codec" 12 | "github.com/pkg/errors" 13 | "strconv" 14 | ) 15 | 16 | type SendTx struct { 17 | ContractName string 18 | MethodName string 19 | Arguments []*Arg 20 | } 21 | 22 | func UnmarshalSendTx(bytes []byte) (*SendTx, error) { 23 | var sendTx *SendTx 24 | err := json.Unmarshal(bytes, &sendTx) 25 | return sendTx, err 26 | } 27 | 28 | func MarshalSendTxResponse(r *codec.SendTransactionResponse, txId string) ([]byte, error) { 29 | outputArgs, err := MarshalArgs(r.OutputArguments) 30 | if err != nil { 31 | return nil, errors.Errorf("Send Tx response marshaling output arguments failed with %s \n", err.Error()) 32 | } 33 | outputEvents, err := MarshalEvents(r.OutputEvents) 34 | if err != nil { 35 | return nil, errors.Errorf("Send Tx response marshaling output events failed with %s \n", err.Error()) 36 | } 37 | return json.MarshalIndent(&struct { 38 | RequestStatus codec.RequestStatus 39 | TxId string 40 | ExecutionResult codec.ExecutionResult 41 | OutputArguments []*Arg 42 | OutputEvents []*Event 43 | TransactionStatus codec.TransactionStatus 44 | BlockHeight string 45 | BlockTimestamp string 46 | }{ 47 | RequestStatus: r.RequestStatus, 48 | TxId: txId, 49 | ExecutionResult: r.ExecutionResult, 50 | OutputArguments: outputArgs, 51 | OutputEvents: outputEvents, 52 | TransactionStatus: r.TransactionStatus, 53 | BlockHeight: strconv.FormatUint(r.BlockHeight, 10), 54 | BlockTimestamp: r.BlockTimestamp.UTC().Format(codec.ISO_DATE_FORMAT), 55 | }, "", " ") 56 | } 57 | -------------------------------------------------------------------------------- /jsoncodec/tx_proof.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "encoding/hex" 11 | "encoding/json" 12 | "github.com/orbs-network/gamma-cli/crypto/digest" 13 | "github.com/orbs-network/orbs-client-sdk-go/codec" 14 | "github.com/pkg/errors" 15 | "strconv" 16 | ) 17 | 18 | func MarshalTxProofResponse(r *codec.GetTransactionReceiptProofResponse) ([]byte, error) { 19 | outputArgs, err := MarshalArgs(r.OutputArguments) 20 | if err != nil { 21 | return nil, errors.Errorf("Tx proof response marshaling output arguments failed with %s \n", err.Error()) 22 | } 23 | outputEvents, err := MarshalEvents(r.OutputEvents) 24 | if err != nil { 25 | return nil, errors.Errorf("Tx proof response marshaling output events failed with %s \n", err.Error()) 26 | } 27 | return json.MarshalIndent(&struct { 28 | RequestStatus codec.RequestStatus 29 | ExecutionResult codec.ExecutionResult 30 | OutputArguments []*Arg 31 | OutputEvents []*Event 32 | TransactionStatus codec.TransactionStatus 33 | BlockHeight string 34 | BlockTimestamp string 35 | PackedProof string 36 | PackedReceipt string 37 | ProofSigners []string 38 | }{ 39 | RequestStatus: r.RequestStatus, 40 | ExecutionResult: r.ExecutionResult, 41 | OutputArguments: outputArgs, 42 | OutputEvents: outputEvents, 43 | TransactionStatus: r.TransactionStatus, 44 | BlockHeight: strconv.FormatUint(r.BlockHeight, 10), 45 | BlockTimestamp: r.BlockTimestamp.UTC().Format(codec.ISO_DATE_FORMAT), 46 | PackedProof: "0x" + hex.EncodeToString(r.PackedProof), 47 | PackedReceipt: "0x" + hex.EncodeToString(r.PackedReceipt), 48 | ProofSigners: getProofSignersFromPackedProof(r.PackedProof), 49 | }, "", " ") 50 | } 51 | 52 | func getProofSignersFromPackedProof(packedProof []byte) []string { 53 | nodeAddresses, err := digest.GetBlockSignersFromReceiptProof(packedProof) 54 | if err != nil { 55 | return nil 56 | } 57 | var res []string 58 | for _, nodeAddress := range nodeAddresses { 59 | signerString := "0x" + hex.EncodeToString(nodeAddress) 60 | res = append(res, signerString) 61 | } 62 | return res 63 | } 64 | -------------------------------------------------------------------------------- /jsoncodec/tx_status.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package jsoncodec 8 | 9 | import ( 10 | "encoding/json" 11 | "github.com/orbs-network/orbs-client-sdk-go/codec" 12 | "github.com/pkg/errors" 13 | "strconv" 14 | ) 15 | 16 | func MarshalTxStatusResponse(r *codec.GetTransactionStatusResponse) ([]byte, error) { 17 | outputArgs, err := MarshalArgs(r.OutputArguments) 18 | if err != nil { 19 | return nil, errors.Errorf("Tx status response marshaling output arguments failed with %s \n", err.Error()) 20 | } 21 | outputEvents, err := MarshalEvents(r.OutputEvents) 22 | if err != nil { 23 | return nil, errors.Errorf("Tx status response marshaling output events failed with %s \n", err.Error()) 24 | } 25 | return json.MarshalIndent(&struct { 26 | RequestStatus codec.RequestStatus 27 | ExecutionResult codec.ExecutionResult 28 | OutputArguments []*Arg 29 | OutputEvents []*Event 30 | TransactionStatus codec.TransactionStatus 31 | BlockHeight string 32 | BlockTimestamp string 33 | }{ 34 | RequestStatus: r.RequestStatus, 35 | ExecutionResult: r.ExecutionResult, 36 | OutputArguments: outputArgs, 37 | OutputEvents: outputEvents, 38 | TransactionStatus: r.TransactionStatus, 39 | BlockHeight: strconv.FormatUint(r.BlockHeight, 10), 40 | BlockTimestamp: r.BlockTimestamp.UTC().Format(codec.ISO_DATE_FORMAT), 41 | }, "", " ") 42 | } 43 | -------------------------------------------------------------------------------- /keys.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "github.com/orbs-network/crypto-lib-go/crypto/encoding" 12 | "github.com/orbs-network/gamma-cli/jsoncodec" 13 | "github.com/orbs-network/orbs-client-sdk-go/orbs" 14 | "io/ioutil" 15 | ) 16 | 17 | func commandGenerateTestKeys(requiredOptions []string) { 18 | keys := make(map[string]*jsoncodec.Key) 19 | for i := 0; i < 10; i++ { 20 | account, err := orbs.CreateAccount() 21 | if err != nil { 22 | die("Could not create Orbs account.") 23 | } 24 | user := fmt.Sprintf("user%d", i+1) 25 | keys[user] = &jsoncodec.Key{ 26 | PrivateKey: encoding.EncodeHex(account.PrivateKey), 27 | PublicKey: encoding.EncodeHex(account.PublicKey), 28 | Address: account.Address, 29 | } 30 | } 31 | 32 | bytes, err := jsoncodec.MarshalKeys(keys) 33 | if err != nil { 34 | die("Could not encode keys to json.\n\n%s", err.Error()) 35 | } 36 | 37 | filename := *flagKeyFile 38 | if filename == "" { 39 | filename = TEST_KEYS_FILENAME 40 | } 41 | err = ioutil.WriteFile(filename, bytes, 0644) 42 | if err != nil { 43 | die("Could not write keys to file.\n\n%s", err.Error()) 44 | } 45 | 46 | if !doesFileExist(filename) { 47 | die("File not found after write.") 48 | } 49 | 50 | log("10 new test keys written successfully to '%s'.\n", filename) 51 | } 52 | 53 | func getTestKeyFromFile(id string) *jsoncodec.RawKey { 54 | if !doesFileExist(*flagKeyFile) { 55 | commandGenerateTestKeys(nil) 56 | } 57 | 58 | bytes, err := ioutil.ReadFile(*flagKeyFile) 59 | if err != nil { 60 | die("Could not open keys file '%s'.\n\n%s", *flagKeyFile, err.Error()) 61 | } 62 | 63 | keys, err := jsoncodec.UnmarshalKeys(bytes) 64 | if err != nil { 65 | die("Failed parsing keys json file '%s'. Try deleting the key file to have it automatically recreated.\n\n%s", *flagKeyFile, err.Error()) 66 | } 67 | 68 | key, found := keys[id] 69 | if !found { 70 | die("Key with id '%s' not found in key file '%s'.", id, *flagKeyFile) 71 | } 72 | 73 | privateKey, err := encoding.DecodeHex(key.PrivateKey) 74 | if err != nil { 75 | die("Could not parse hex string '%s'. Try deleting the key file '%s' to have it automatically recreated.\n\n%s", privateKey, *flagKeyFile, err.Error()) 76 | } 77 | 78 | publicKey, err := encoding.DecodeHex(key.PublicKey) 79 | if err != nil { 80 | die("Could not parse hex string '%s'. Try deleting the key file '%s' to have it automatically recreated.\n\n%s", publicKey, *flagKeyFile, err.Error()) 81 | } 82 | 83 | address, err := encoding.DecodeHex(key.Address) 84 | if err != nil { 85 | die("Could not parse hex string '%s'. Try deleting the key file '%s' to have it automatically recreated.\n\n%s", address, *flagKeyFile, err.Error()) 86 | } 87 | 88 | res := &jsoncodec.RawKey{ 89 | PrivateKey: privateKey, 90 | PublicKey: publicKey, 91 | Address: address, 92 | } 93 | 94 | return res 95 | } 96 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "flag" 11 | "fmt" 12 | "os" 13 | "strings" 14 | ) 15 | 16 | var GAMMA_CLI_VERSION string 17 | const CONFIG_FILENAME = "orbs-gamma-config.json" 18 | const TEST_KEYS_FILENAME = "orbs-test-keys.json" 19 | const LOCAL_ENV_ID = "local" 20 | const EXPERIMENTAL_ENV_ID = "experimental" 21 | 22 | type handlerOptions struct { 23 | name string 24 | 25 | dockerRepo string 26 | dockerCmd []string 27 | containerName string 28 | dockerRegistryTagsUrl string 29 | 30 | env []string 31 | 32 | port int 33 | containerPort int 34 | } 35 | 36 | type handler func([]string) 37 | 38 | type command struct { 39 | desc string 40 | args string 41 | example string 42 | example2 string 43 | handler 44 | sort int 45 | requiredOptions []string 46 | } 47 | 48 | func gammaHandlerOptions() handlerOptions { 49 | return handlerOptions{ 50 | name: "Orbs Gamma personal blockchain", 51 | dockerRepo: "orbsnetwork/gamma", 52 | dockerCmd: []string{"./gamma-server", "-override-config", *flagOverrideConfig}, 53 | containerName: "orbs-gamma-server", 54 | dockerRegistryTagsUrl: "https://registry.hub.docker.com/v2/repositories/orbsnetwork/gamma/tags/", 55 | port: *flagPort, 56 | containerPort: 8080, 57 | } 58 | } 59 | 60 | func prismHandlerOptions() handlerOptions { 61 | return handlerOptions{ 62 | name: "Prism blockchain explorer", 63 | dockerRepo: "orbsnetwork/prism", 64 | containerName: "orbs-prism", 65 | dockerRegistryTagsUrl: "https://registry.hub.docker.com/v2/repositories/orbsnetwork/prism/tags/", 66 | port: *flagPrismPort, 67 | containerPort: 3000, 68 | env: []string{ 69 | "ORBS_VIRTUAL_CHAIN_ID=42", 70 | "NODE_ENV=staging", 71 | "DATABASE_TYPE=inmemory", 72 | "GAP_FILLER_ACTIVE=true", 73 | fmt.Sprintf("ORBS_ENDPOINT=http://orbs-gamma-server:8080"), 74 | }, 75 | } 76 | } 77 | 78 | var commands = map[string]*command{ 79 | "start-local": { 80 | desc: "start a local Orbs personal blockchain instance listening on port", 81 | args: "-port -override-config {json}", 82 | example: "gamma-cli start-local -port 8080", 83 | handler: commandStartLocal, 84 | sort: 0, 85 | requiredOptions: nil, 86 | }, 87 | "stop-local": { 88 | desc: "stop a locally running Orbs personal blockchain instance", 89 | handler: commandStopLocal, 90 | sort: 1, 91 | requiredOptions: nil, 92 | }, 93 | "gen-test-keys": { 94 | desc: "generate a new batch of 10 test keys and store in " + TEST_KEYS_FILENAME + " (default filename)", 95 | args: "-keys [OUTPUT_FILE]", 96 | example: "gamma-cli gen-test-keys -keys " + TEST_KEYS_FILENAME, 97 | handler: commandGenerateTestKeys, 98 | sort: 2, 99 | requiredOptions: nil, 100 | }, 101 | "deploy": { 102 | desc: "deploy a smart contract with the code specified in the source file ", 103 | args: " -name [CONTRACT_NAME] -signer [ID_FROM_KEYS_JSON]", 104 | example: "gamma-cli deploy MyToken.go -signer user1", 105 | example2: "gamma-cli deploy contract.go -name MyToken", 106 | handler: commandDeploy, 107 | sort: 3, 108 | requiredOptions: []string{" - path of file with source code"}, 109 | }, 110 | "send-tx": { 111 | desc: "sign and send the transaction specified in the JSON file ", 112 | args: " -arg# [OVERRIDE_ARG_#] -signer [ID_FROM_KEYS_JSON]", 113 | example: "gamma-cli send-tx transfer.json -signer user1", 114 | example2: "gamma-cli send-tx transfer.json -arg2 0x5B63Ca66637316A0D7f84Ebf60E50963c10059aD", 115 | handler: commandSendTx, 116 | sort: 4, 117 | requiredOptions: []string{" - path of JSON file with transaction details"}, 118 | }, 119 | "run-query": { 120 | desc: "read state or run a read-only contract method as specified in the JSON file ", 121 | args: " -arg# [OVERRIDE_ARG_#] -signer [ID_FROM_KEYS_JSON]", 122 | example: "gamma-cli run-query get-balance.json -signer user1", 123 | example2: "gamma-cli run-query get-balance.json -arg1 0x5B63Ca66637316A0D7f84Ebf60E50963c10059aD", 124 | handler: commandRunQuery, 125 | sort: 5, 126 | requiredOptions: []string{" - path of JSON file with query details"}, 127 | }, 128 | "tx-status": { 129 | desc: "get the current status of a sent transaction with txid (from send-tx response)", 130 | args: "", 131 | example: "gamma-cli tx-status 0xB68fa95B7f397815Ddf41150d79b27a888448a22e08DeAf8600E7a495c406303659f8C3782614660", 132 | handler: commandTxStatus, 133 | sort: 6, 134 | requiredOptions: []string{" - txid of previously sent transaction, from send-tx response"}, 135 | }, 136 | "tx-proof": { 137 | desc: "get cryptographic proof for transaction receipt with txid (from send-tx response)", 138 | args: "", 139 | example: "gamma-cli tx-proof 0xB68fa95B7f397815Ddf41150d79b27a888448a22e08DeAf8600E7a495c406303659f8C3782614660", 140 | handler: commandTxProof, 141 | sort: 7, 142 | requiredOptions: []string{" - txid of previously sent transaction, from send-tx response"}, 143 | }, 144 | "upgrade-server": { 145 | desc: "upgrade to the latest stable version of Gamma server", 146 | example: "gamma-cli upgrade-server", 147 | example2: "gamma-cli upgrade-server -env experimental", 148 | handler: commandUpgrade, 149 | sort: 8, 150 | requiredOptions: nil, 151 | }, 152 | "logs": { 153 | desc: "streams logs from gamma that are printed by smart contract to stdout (i.e. println())", 154 | handler: showLogs, 155 | sort: 9, 156 | example: "gamma-cli logs", 157 | requiredOptions: nil, 158 | }, 159 | "version": { 160 | desc: "print gamma-cli and Gamma server versions", 161 | handler: commandVersion, 162 | sort: 10, 163 | requiredOptions: nil, 164 | }, 165 | "help": { 166 | desc: "print this help screen", 167 | sort: 11, 168 | requiredOptions: nil, 169 | }, 170 | } 171 | 172 | var ( 173 | flagPort = flag.Int("port", 8080, "listening port for Gamma server") 174 | flagPrismPort = flag.Int("prismPort", 3000, "listening port for Prism blockchain explorer") 175 | flagSigner = flag.String("signer", "user1", "id of the signing key from the test key json") 176 | flagContractName = flag.String("name", "", "name of the smart contract being deployed") 177 | flagKeyFile = flag.String("keys", TEST_KEYS_FILENAME, "name of the json file containing test keys") 178 | flagConfigFile = flag.String("config", CONFIG_FILENAME, "path to config file") 179 | flagEnv = flag.String("env", LOCAL_ENV_ID, "environment from config file containing server connection details") 180 | flagWait = flag.Bool("wait", false, "wait until Gamma server is ready and listening") 181 | flagNoUi = flag.Bool("no-ui", false, "do not start Prism blockchain explorer") 182 | flagOverrideConfig = flag.String("override-config", "{}", "option json for overriding config values, same format as file-based config") 183 | 184 | // args (hidden from help) 185 | flagArg1 = flag.String("arg1", "", "") 186 | flagArg2 = flag.String("arg2", "", "") 187 | flagArg3 = flag.String("arg3", "", "") 188 | flagArg4 = flag.String("arg4", "", "") 189 | flagArg5 = flag.String("arg5", "", "") 190 | flagArg6 = flag.String("arg6", "", "") 191 | flagArg7 = flag.String("arg7", "", "") 192 | flagArg8 = flag.String("arg8", "", "") 193 | flagArg9 = flag.String("arg9", "", "") 194 | ) 195 | 196 | func main() { 197 | flag.Usage = func() { commandShowHelp(nil) } 198 | commands["help"].handler = commandShowHelp 199 | 200 | if len(os.Args) <= 1 { 201 | commandShowHelp(nil) 202 | } 203 | cmdName := os.Args[1] 204 | cmd, found := commands[cmdName] 205 | if !found { 206 | die("Command '%s' not found, run 'gamma-cli help' to see available commands.", cmdName) 207 | } 208 | 209 | requiredOptions := []string{} 210 | if len(cmd.requiredOptions) > 0 { 211 | if len(os.Args) < 2+len(cmd.requiredOptions) { 212 | die("Command '%s' is missing required arguments %v.", cmdName, cmd.requiredOptions) 213 | } 214 | requiredOptions = os.Args[2 : 2+len(cmd.requiredOptions)] 215 | for i, requiredOption := range requiredOptions { 216 | if strings.HasPrefix(requiredOption, "-") { 217 | die("Command '%s' argument %d should be %s.", cmdName, i+1, cmd.requiredOptions[i]) 218 | } 219 | } 220 | } 221 | 222 | os.Args = os.Args[2+len(cmd.requiredOptions)-1:] 223 | flag.Parse() 224 | 225 | cmd.handler(requiredOptions) 226 | } 227 | 228 | func log(format string, args ...interface{}) { 229 | fmt.Fprintf(os.Stdout, format, args...) 230 | fmt.Fprintf(os.Stdout, "\n") 231 | } 232 | 233 | func die(format string, args ...interface{}) { 234 | fmt.Fprintf(os.Stderr, "ERROR:\n ") 235 | fmt.Fprintf(os.Stderr, format, args...) 236 | fmt.Fprintf(os.Stderr, "\n\n") 237 | os.Exit(2) 238 | } 239 | 240 | func exit() { 241 | os.Exit(0) 242 | } 243 | 244 | func doesFileExist(filename string) bool { 245 | _, err := os.Stat(filename) 246 | return !os.IsNotExist(err) 247 | } 248 | -------------------------------------------------------------------------------- /marketplace/gamma-devkit-google-deployment-guide.md: -------------------------------------------------------------------------------- 1 | # Google Cloud Launcher 2 | This guide will cover the basics (and more!) of deploying the Orbs Gamma Testkit atop Google Cloud Platform from the GCP Marketplace using the Google Cloud Launcher. As a part of this guide, we will be deploying an instance of the kit, verify that it's running correctly and get a taste of how to develop and test your smart contracts using it to emphasize just how easy it is to develop on blockchain with Orbs! 3 | 4 | ## Deploying 5 | First, we're going to deploy an Orbs development kit. 6 | The kit consists of: 7 | * Gamma server - Our development local blockchain which stores our data and answers our calls) 8 | * Gamma CLI - The CLI allows us to easily deploy contracts onto the blockchain and perform calls against our deployed contract. 9 | * Prism - Orbs' block explorer, which provides visibility into blocks and transactions which have been registered on our network. 10 | 11 | Deploying is easy with Cloud Launcher: Go to https://console.cloud.google.com/launcher/details/orbsltd-public/orbs-gamma-devkit 12 | 13 | ![](./images/step01.png) 14 | 15 | Click "Launch on Compute Engine" 16 | 17 | ![](./images/step02.png) 18 | 19 | You can take the default settings or customize them. When complete click "Deploy" 20 | 21 | ![](./images/step03.png) 22 | 23 | That's it! Your development kit is now deploying. 24 | 25 | ## Inspecting the kit once it's running 26 | 27 | When the deployment is complete, you should see: 28 | 29 | ![](./images/step04.png) 30 | 31 | Note: Gamma, the development server, is configured to close a block once every 10 minutes or so, OR when at least 1 transaction is pushed through with an API call. 32 | 33 | At this point, you can open a web browser and view Prism to see block activity. Click on the "Visit the site" button. 34 | 35 | ![](./images/step05.png) 36 | 37 | Once the browser has finished loading, it should look like: 38 | 39 | ![](./images/step06.png) 40 | 41 | You should see a few blocks. That's great as it shows our development kit is working and closing blocks. 42 | 43 | That means we can start to play around with it. 44 | 45 | The next kind of interaction we can have with our development kit is to deploy a smart contract into the blockchain and interact with it. 46 | 47 | ## Developing with the deployed development kit 48 | 49 | At the moment Prism and our Blockchain server are running and looks to be closing blocks, which means it's healthy. 50 | 51 | Next, we connect to the machine running our Gamma server so we can use Gamma CLI and deploy our first contract. We'll do so by clicking on "Connect": 52 | 53 | ![](./images/step07.png) 54 | 55 | Google Cloud negotiates the SSH keys between our browser and the target machine in about 10 seconds. There are other means of accessing the machine via SSH. We are merely illustrating the most straightforward approach here for the sake of keeping things simple. 56 | 57 | ![](./images/step08.png) 58 | 59 | Once inside the machine, our Terminal (which is in a new pop up window) should look like the following: 60 | 61 | ![](./images/step09.png) 62 | 63 | Let's get some example contracts from [Orbs Contract SDK](https://github.com/orbs-network/orbs-contract-sdk) repository by running `git clone https://github.com/orbs-network/orbs-contract-sdk.git` within the terminal window. 64 | 65 | (Tip: you might be prompted to approve the authenticity of github.com. Type `yes` into the Terminal if asked.) 66 | 67 | ![](./images/step10.png) 68 | 69 | Let's navigate to the examples folder and into the Counter contract by typing `cd orbs-contract-sdk/go/examples/counter/` into the terminal window. The Counter contract is a very simple contract that initializes an empty state variable, which we can be increased with a call to the `add()` function. In addition, we can also access the current counter value by invoking a call to the contract's `get()` function. 70 | 71 | In the Terminal you should be located at the folder containing the file `contract.go`. Let's verify this by typing `ls -lh` into the Terminal to ensure we can see the file is there. 72 | 73 | ![](./images/step11.png) 74 | 75 | Next, we can deploy the contract into our Gamma server by typing the following command: `gamma-cli deploy contract.go -name MyCounter` and wait for it to finish. Once finished, Gamma CLI will return a JSON output object representing the result of our transaction against the server. Which (if all is successful) should look similar to the following 76 | 77 | ![](./images/step12.png) 78 | 79 | Please note the 2 most important properties in the JSON object: 80 | 81 | * The `ExecutionResult` provides the most basic kind of proof that the request was successful or not. In this case, we can see that the call was successful. 82 | * The `TransactionStatus` is very important. Since this is a blockchain, our transaction might not have been committed into any block yet which means it is not final, and therefore might be pending (or worse - not accepted at all into the ledger). In our case, we can see it's in the `COMMITTED` state so we can rest assure our contract is deployed successfully! 83 | 84 | Congrats! You have successfully deployed your first smart contract! How easy was that?!? 85 | 86 | Ok so what's next? If we look closely at our smart contract code, we can see it's initializing the counter value with a value of `0`. 87 | 88 | ![](./images/step13.png) 89 | 90 | Since our contract is now deployed, let's try and "read" the current value of the counter to make sure we get a value of `0` back. 91 | 92 | Gamma CLI uses a JSON file to represent the action details we're requesting against the blockchain. Our Counter example has JSON files ready for us to experiment with. The `get()` method doesn't need any arguments. The JSON descriptor file is quite easy to understand. Let's have a look at it: 93 | 94 | Type into the terminal window `cat json/get.json` (cat is a command in Linux to view the content of a file) 95 | 96 | ![](./images/step14.png) 97 | 98 | Note that this file is specifically asking to invoke the `get()` method of the `MyCounter` contract. That name is important as we used it previously to name our contract upon deployment. If you chose a different name, you have to edit this file before sending a request with Gamma CLI using this file. 99 | 100 | Alright, so now that we have some sense about what gamma is using to send our request to the local blockchain server (Gamma), let's issue a "Query" call and invoke the `get()` command of our contract. 101 | 102 | We do that by typing in the terminal `gamma-cli run-query json/get.json` 103 | 104 | ![](./images/step15.png) 105 | 106 | Again, the returned output contains a bit of information. We've highlighted what's most important for us at this stage, and that's the current value of the counter state variable. We know it's supposed to be 0, but we wanted to verify that. Indeed as it appears by the highlighted red rectangle, the value is a `uint64` (a native number) of `0`. 107 | 108 | All looks good so far! 109 | 110 | Now let's make things interesting by running a transaction that adds '25` to that lonely `0` to increase the counter! 111 | 112 | As before, let's view how the JSON file to describe this action is represented for Gamma CLI to use by typing `cat json/add-25.json` 113 | 114 | ![](./images/step16.png) 115 | 116 | Notice how we have an argument in this call in the form of a `uint64` (native number) with a value of 25, which will be added to the counter upon running this transaction with Gamma CLI. 117 | 118 | To make this happen, we issue the request with Gamma CLI by typing the following into the Terminal: `gamma-cli send-tx json/add-25.json` 119 | 120 | and the input from this call should look something similar to the following: 121 | 122 | ![](./images/step17.png) 123 | 124 | As you can see, the response seems to be successful! We've got an `ExecutionResult` of `SUCCESS`, which is excellent. It means our transaction went through and was also `COMMITTED` into a block which is accepted by the network there being committed to the ledger. That's great news! We've modified the state of our contract now and updated the counter variable in its state to represent a different value (25). 125 | 126 | Let's verify this is indeed the reality by issuing another `get()` call and assert that we get 25 and not 0 as before. 127 | 128 | ![](./images/step18.png) 129 | 130 | Yes! 131 | As expected we can see that the blockchain has returned us the current value of the counter, and it's now standing on 25 instead of the previous 0 that it once was. So everything is working! 132 | 133 | ## Next Steps 134 | 135 | You've probably noticed that we've used `send-tx` and `run-query` on some of these calls. The `send-tx` is used for transactions which aim to change the state of a contract and perform and actual action. Whereas the `run-query` calls are usually "reading" information that is already present and doesn't require the heavy lifting of the consensus process to occur between the blockchain nodes as happens on a transaction. 136 | 137 | To read more about this and learn more about blockchain in general and how to move forward into more complex examples using Orbs be sure to [visit our GitBook](https://orbs.gitbook.io/contract-sdk/). 138 | 139 | To learn more about Orbs and it's mission feel free to [visit our website](https://www.orbs.com/). 140 | -------------------------------------------------------------------------------- /marketplace/images/step01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step01.png -------------------------------------------------------------------------------- /marketplace/images/step02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step02.png -------------------------------------------------------------------------------- /marketplace/images/step03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step03.png -------------------------------------------------------------------------------- /marketplace/images/step04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step04.png -------------------------------------------------------------------------------- /marketplace/images/step05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step05.png -------------------------------------------------------------------------------- /marketplace/images/step06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step06.png -------------------------------------------------------------------------------- /marketplace/images/step07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step07.png -------------------------------------------------------------------------------- /marketplace/images/step08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step08.png -------------------------------------------------------------------------------- /marketplace/images/step09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step09.png -------------------------------------------------------------------------------- /marketplace/images/step10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step10.png -------------------------------------------------------------------------------- /marketplace/images/step11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step11.png -------------------------------------------------------------------------------- /marketplace/images/step12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step12.png -------------------------------------------------------------------------------- /marketplace/images/step13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step13.png -------------------------------------------------------------------------------- /marketplace/images/step14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step14.png -------------------------------------------------------------------------------- /marketplace/images/step15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step15.png -------------------------------------------------------------------------------- /marketplace/images/step16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step16.png -------------------------------------------------------------------------------- /marketplace/images/step17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step17.png -------------------------------------------------------------------------------- /marketplace/images/step18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orbs-network/gamma-cli/700a7eff99b768491e35058853a66ae399d778f3/marketplace/images/step18.png -------------------------------------------------------------------------------- /marketplace/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Cleanup a gamma-server container in case there is one 4 | docker rm -fv orbs-gamma-server orbs-prism 5 | docker pull orbsnetwork/gamma:v1.2.2 6 | 7 | GAMMA_CLI_VERSION="v0.9.0" 8 | GAMMA_CLI_URL="https://github.com/orbs-network/gamma-cli/releases/download/$GAMMA_CLI_VERSION/gammacli-linux-x86-64-$GAMMA_CLI_VERSION.tar.gz" 9 | 10 | echo "Downloading pre-built gamma-cli ($GAMMA_CLI_VERSION) from it's official GitHub release repository.." 11 | wget $GAMMA_CLI_URL 12 | tar -zxvf "gammacli-linux-x86-64-$GAMMA_CLI_VERSION.tar.gz" 13 | sudo mv _bin/gamma-cli /usr/bin/gamma-cli 14 | 15 | echo "gamma-cli and gamma-server successfully installed" 16 | 17 | gamma-cli start-local 18 | -------------------------------------------------------------------------------- /public_api.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | "github.com/orbs-network/gamma-cli/jsoncodec" 13 | "github.com/orbs-network/orbs-client-sdk-go/codec" 14 | "github.com/orbs-network/orbs-client-sdk-go/orbs" 15 | "github.com/pkg/errors" 16 | "io/ioutil" 17 | "net" 18 | "net/url" 19 | "os" 20 | "path" 21 | "strings" 22 | "syscall" 23 | ) 24 | 25 | const DEPLOY_SYSTEM_CONTRACT_NAME = "_Deployments" 26 | const DEPLOY_SYSTEM_METHOD_NAME = "deployService" 27 | const PROCESSOR_TYPE_NATIVE = uint32(1) 28 | const PROCESSOR_TYPE_JAVASCRIPT = uint32(2) 29 | 30 | func _getSource(name string) (code [][]byte, err error) { 31 | if info, err := os.Stat(name); err != nil { 32 | return nil, err 33 | } else if info.IsDir() { 34 | return orbs.ReadSourcesFromDir(name) 35 | } else { 36 | singleFile, err := ioutil.ReadFile(name) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | return [][]byte{singleFile}, err 42 | } 43 | } 44 | 45 | func commandDeploy(requiredOptions []string) { 46 | codeFile := requiredOptions[0] 47 | 48 | if *flagContractName == "" { 49 | *flagContractName = getFilenameWithoutExtension(codeFile) 50 | } 51 | 52 | code, err := _getSource(codeFile) 53 | if err != nil { 54 | die("Could not find path\n\n%s", err.Error()) 55 | } 56 | 57 | signer := getTestKeyFromFile(*flagSigner) 58 | 59 | client := createOrbsClient() 60 | 61 | payload, txId, err := client.CreateDeployTransaction(signer.PublicKey, signer.PrivateKey, string(*flagContractName), orbs.PROCESSOR_TYPE_NATIVE, code...) 62 | if err != nil { 63 | die("Could not encode payload of the message about to be sent to server.\n\n%s", err.Error()) 64 | } 65 | 66 | response, clientErr := client.SendTransaction(payload) 67 | handleNoConnectionGracefully(clientErr, client) 68 | if response != nil { 69 | output, err := jsoncodec.MarshalSendTxResponse(response, txId) 70 | if err != nil { 71 | die("Could not encode send-tx response to json.\n\n%s", err.Error()) 72 | } 73 | 74 | log("%s\n", string(output)) 75 | exit() 76 | } 77 | 78 | if clientErr != nil { 79 | die("Request transaction failed on server.\n\n%s", clientErr.Error()) 80 | } 81 | } 82 | 83 | func commandSendTx(requiredOptions []string) { 84 | inputFile := requiredOptions[0] 85 | 86 | signer := getTestKeyFromFile(*flagSigner) 87 | 88 | bytes, err := ioutil.ReadFile(inputFile) 89 | if err != nil { 90 | die("Could not open input file.\n\n%s", err.Error()) 91 | } 92 | 93 | sendTx, err := jsoncodec.UnmarshalSendTx(bytes) 94 | if err != nil { 95 | die("Failed parsing input json file '%s'.\n\n%s", inputFile, err.Error()) 96 | } 97 | 98 | // override contract name 99 | if *flagContractName != "" { 100 | sendTx.ContractName = *flagContractName 101 | } 102 | 103 | overrideArgsWithFlags(sendTx.Arguments) 104 | inputArgs, err := jsoncodec.UnmarshalArgs(sendTx.Arguments, getTestKeyFromFile) 105 | if err != nil { 106 | die(err.Error()) 107 | } 108 | 109 | client := createOrbsClient() 110 | 111 | payload, txId, err := client.CreateTransaction(signer.PublicKey, signer.PrivateKey, sendTx.ContractName, sendTx.MethodName, inputArgs...) 112 | if err != nil { 113 | die("Could not encode payload of the message about to be sent to server.\n\n%s", err.Error()) 114 | } 115 | 116 | response, clientErr := client.SendTransaction(payload) 117 | handleNoConnectionGracefully(clientErr, client) 118 | if response != nil { 119 | output, err := jsoncodec.MarshalSendTxResponse(response, txId) 120 | if err != nil { 121 | die("Could not encode send-tx response to json.\n\n%s", err.Error()) 122 | } 123 | 124 | log("%s\n", string(output)) 125 | exit() 126 | } 127 | 128 | if clientErr != nil { 129 | die("Request send-tx failed on server.\n\n%s", clientErr.Error()) 130 | } 131 | } 132 | 133 | func commandRunQuery(requiredOptions []string) { 134 | inputFile := requiredOptions[0] 135 | 136 | signer := getTestKeyFromFile(*flagSigner) 137 | 138 | bytes, err := ioutil.ReadFile(inputFile) 139 | if err != nil { 140 | die("Could not open input file.\n\n%s", err.Error()) 141 | } 142 | 143 | runQuery, err := jsoncodec.UnmarshalRead(bytes) 144 | if err != nil { 145 | die("Failed parsing input json file '%s'.\n\n%s", inputFile, err.Error()) 146 | } 147 | 148 | // override contract name 149 | if *flagContractName != "" { 150 | runQuery.ContractName = *flagContractName 151 | } 152 | 153 | overrideArgsWithFlags(runQuery.Arguments) 154 | inputArgs, err := jsoncodec.UnmarshalArgs(runQuery.Arguments, getTestKeyFromFile) 155 | if err != nil { 156 | die(err.Error()) 157 | } 158 | 159 | client := createOrbsClient() 160 | 161 | payload, err := client.CreateQuery(signer.PublicKey, runQuery.ContractName, runQuery.MethodName, inputArgs...) 162 | if err != nil { 163 | die("Could not encode payload of the message about to be sent to server.\n\n%s", err.Error()) 164 | } 165 | 166 | response, clientErr := client.SendQuery(payload) 167 | handleNoConnectionGracefully(clientErr, client) 168 | if response != nil { 169 | output, err := jsoncodec.MarshalReadResponse(response) 170 | if err != nil { 171 | die("Could not encode run-query response to json.\n\n%s", err.Error()) 172 | } 173 | 174 | log("%s\n", string(output)) 175 | exit() 176 | } 177 | 178 | if clientErr != nil { 179 | die("Request run-query failed on server.\n\n%s", clientErr.Error()) 180 | } 181 | } 182 | 183 | func commandTxStatus(requiredOptions []string) { 184 | txId := requiredOptions[0] 185 | 186 | client := createOrbsClient() 187 | 188 | response, clientErr := client.GetTransactionStatus(txId) 189 | handleNoConnectionGracefully(clientErr, client) 190 | if response != nil { 191 | output, err := jsoncodec.MarshalTxStatusResponse(response) 192 | if err != nil { 193 | die("Could not encode status response to json.\n\n%s", err.Error()) 194 | } 195 | 196 | log("%s\n", string(output)) 197 | exit() 198 | } 199 | 200 | if clientErr != nil { 201 | die("Request status failed on server.\n\n%s", clientErr.Error()) 202 | } 203 | } 204 | 205 | func commandTxProof(requiredOptions []string) { 206 | txId := requiredOptions[0] 207 | 208 | client := createOrbsClient() 209 | 210 | response, clientErr := client.GetTransactionReceiptProof(txId) 211 | handleNoConnectionGracefully(clientErr, client) 212 | if response != nil { 213 | output, err := jsoncodec.MarshalTxProofResponse(response) 214 | if err != nil { 215 | die("Could not encode tx proof response to json.\n\n%s", err.Error()) 216 | } 217 | 218 | log("%s\n", string(output)) 219 | exit() 220 | } 221 | 222 | if clientErr != nil { 223 | die("Request status failed on server.\n\n%s", clientErr.Error()) 224 | } 225 | } 226 | 227 | func createOrbsClient() *orbs.OrbsClient { 228 | env := getEnvironmentFromConfigFile(*flagEnv) 229 | if len(env.Endpoints) == 0 { 230 | die("Environment Endpoints key does not contain any endpoints.") 231 | } 232 | 233 | endpoint := env.Endpoints[0] 234 | if endpoint == "localhost" { 235 | if !isDockerContainerRunning(gammaHandlerOptions().containerName) && !isPortListening(gammaHandlerOptions().port) { 236 | die("Local Gamma server is not running, use 'gamma-cli start-local' to start it.") 237 | } 238 | endpoint = fmt.Sprintf("http://localhost:%d", gammaHandlerOptions().port) 239 | } 240 | 241 | return orbs.NewClient(endpoint, env.VirtualChain, codec.NETWORK_TYPE_TEST_NET) 242 | } 243 | 244 | // Will get to it when we implement JS 245 | func getProcessorTypeFromFilename(filename string) uint32 { 246 | if strings.HasSuffix(filename, ".go") { 247 | return PROCESSOR_TYPE_NATIVE 248 | } 249 | if strings.HasSuffix(filename, ".js") { 250 | return PROCESSOR_TYPE_JAVASCRIPT 251 | } 252 | die("Unsupported code file type.\n\nSupported code file extensions are: .go .js") 253 | return 0 254 | } 255 | 256 | // TODO: this needs to be simplified 257 | func handleNoConnectionGracefully(err error, client *orbs.OrbsClient) { 258 | msg := fmt.Sprintf("Cannot connect to server at endpoint %s\n\nPlease check that:\n - The server is started and running (if just started, may need a second to initialize).\n - The server is accessible over the network.\n - The endpoint is properly configured if a config file is used.", client.Endpoint) 259 | switch err := errors.Cause(err).(type) { 260 | case *url.Error: 261 | die(msg) 262 | case *net.OpError: 263 | if err.Op == "dial" || err.Op == "read" { 264 | die(msg) 265 | } 266 | case net.Error: 267 | if err.Timeout() { 268 | die(msg) 269 | } 270 | case syscall.Errno: 271 | if err == syscall.ECONNREFUSED { 272 | die(msg) 273 | } 274 | default: 275 | if err == orbs.NoConnectionError { 276 | die(msg) 277 | } 278 | return 279 | } 280 | } 281 | 282 | func getFilenameWithoutExtension(filename string) string { 283 | return strings.Split(path.Base(filename), ".")[0] 284 | } 285 | 286 | func overrideArgWithPossibleArray(arg *jsoncodec.Arg, value string) { 287 | if strings.HasSuffix(arg.Type, "Array") { 288 | var valueAsArray []interface{} 289 | err := json.Unmarshal([]byte(value), &valueAsArray) 290 | if err != nil { 291 | die(fmt.Sprintf("Input is marked as %s but was not set as array of strings\n", arg.Type)) 292 | } 293 | arg.Value = valueAsArray 294 | } else { 295 | arg.Value = value 296 | } 297 | } 298 | 299 | func overrideArgsWithFlags(args []*jsoncodec.Arg) { 300 | if *flagArg1 != "" { 301 | overrideArgWithPossibleArray(args[0], *flagArg1) 302 | } 303 | if *flagArg2 != "" { 304 | overrideArgWithPossibleArray(args[1], *flagArg2) 305 | } 306 | if *flagArg3 != "" { 307 | overrideArgWithPossibleArray(args[2], *flagArg3) 308 | } 309 | if *flagArg4 != "" { 310 | overrideArgWithPossibleArray(args[3], *flagArg4) 311 | } 312 | if *flagArg5 != "" { 313 | overrideArgWithPossibleArray(args[4], *flagArg5) 314 | } 315 | if *flagArg6 != "" { 316 | overrideArgWithPossibleArray(args[5], *flagArg6) 317 | } 318 | if *flagArg7 != "" { 319 | overrideArgWithPossibleArray(args[6], *flagArg7) 320 | } 321 | if *flagArg8 != "" { 322 | overrideArgWithPossibleArray(args[7], *flagArg8) 323 | } 324 | if *flagArg9 != "" { 325 | overrideArgWithPossibleArray(args[8], *flagArg9) 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -xe 2 | 3 | go test ./... -v 4 | -------------------------------------------------------------------------------- /test/_arguments/arguments.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the orbs-network-go authors 2 | // This file is part of the orbs-network-go library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | // Contract that shows that contract with public function that accept and return argument as slices of types 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "github.com/orbs-network/orbs-contract-sdk/go/sdk/v1" 13 | "math/big" 14 | ) 15 | 16 | var PUBLIC = sdk.Export(get, check) 17 | var SYSTEM = sdk.Export(_init) 18 | 19 | func _init() { 20 | } 21 | 22 | var boolArray = []bool{true, false, true, false, false, true} 23 | var uint32Array = []uint32{1, 10, 100, 1000, 10000, 100000, 3} 24 | var uint64Array = []uint64{1, 10, 100, 1000, 10000, 100000, 3} 25 | var uint256Array = []*big.Int{big.NewInt(1), big.NewInt(4194304)} 26 | var stringArray = []string{"picture", "yourself", "in", "a", "boat", "on", "a", "river"} 27 | var bytesArray = [][]byte{{0x11, 0x12}, {0xa, 0xb, 0xc, 0xd}, {0x1, 0x2}} 28 | var bytes20Array = [][20]byte{{0xaa, 0xbb}, {0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 29 | 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01}, {0x1, 0x2}} 30 | var bytes32Array = [][32]byte{{0x11, 0x12}, {0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x04, 31 | 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, 0x04}, {0xa, 0xb, 0xc, 0xd}} 32 | 33 | func get() ([]bool, []uint32, []uint64, []*big.Int, []string, [][]byte, [][20]byte, [][32]byte) { 34 | return boolArray, uint32Array, uint64Array, uint256Array, stringArray, bytesArray, bytes20Array, bytes32Array 35 | } 36 | 37 | func check(boolsIn []bool, uint32sIn []uint32, uint64sIn []uint64, uint256sIn []*big.Int, stringsIn []string, 38 | bytesIn [][]byte, bytes20In [][20]byte, bytes32In [][32]byte) (bool, string) { 39 | if !checkBools(boolsIn) { 40 | return false, "bools" 41 | } 42 | if !checkUint32s(uint32sIn) { 43 | return false, "uint32s" 44 | } 45 | if !checkUint64s(uint64sIn) { 46 | return false, "uint64s" 47 | } 48 | if !checkUint256s(uint256sIn) { 49 | return false, "uint256s" 50 | } 51 | if !checkStrings(stringsIn) { 52 | return false, "strings" 53 | } 54 | if !checkBytes(bytesIn) { 55 | return false, "bytes" 56 | } 57 | if !checkBytes20s(bytes20In) { 58 | return false, "bytes20s" 59 | } 60 | if !checkBytes32s(bytes32In) { 61 | return false, "bytes32s" 62 | } 63 | return true, "" 64 | } 65 | 66 | func checkBools(in []bool) bool { 67 | if len(in) != len(boolArray) { 68 | return false 69 | } 70 | for i := range boolArray { 71 | if boolArray[i] != in[i] { 72 | return false 73 | } 74 | } 75 | return true 76 | } 77 | 78 | func checkUint32s(in []uint32) bool { 79 | if len(in) != len(uint32Array) { 80 | return false 81 | } 82 | for i := range uint32Array { 83 | if uint32Array[i] != in[i] { 84 | return false 85 | } 86 | } 87 | return true 88 | } 89 | 90 | func checkUint64s(in []uint64) bool { 91 | if len(in) != len(uint64Array) { 92 | return false 93 | } 94 | for i := range uint64Array { 95 | if uint64Array[i] != in[i] { 96 | return false 97 | } 98 | } 99 | return true 100 | } 101 | 102 | func checkUint256s(in []*big.Int) bool { 103 | if len(in) != len(uint256Array) { 104 | return false 105 | } 106 | for i := range uint256Array { 107 | if uint256Array[i].Cmp(in[i]) != 0 { 108 | return false 109 | } 110 | } 111 | return true 112 | } 113 | 114 | func checkStrings(in []string) bool { 115 | if len(in) != len(stringArray) { 116 | return false 117 | } 118 | for i := range stringArray { 119 | if stringArray[i] != in[i] { 120 | return false 121 | } 122 | } 123 | return true 124 | } 125 | 126 | func checkBytes(in [][]byte) bool { 127 | if len(in) != len(bytesArray) { 128 | return false 129 | } 130 | for i := range bytesArray { 131 | if !bytes.Equal(bytesArray[i], in[i]) { 132 | return false 133 | } 134 | } 135 | return true 136 | } 137 | 138 | func checkBytes20s(in [][20]byte) bool { 139 | if len(in) != len(bytes20Array) { 140 | return false 141 | } 142 | for i := range bytes20Array { 143 | if !bytes.Equal(bytes20Array[i][:], in[i][:]) { 144 | return false 145 | } 146 | } 147 | return true 148 | } 149 | 150 | func checkBytes32s(in [][32]byte) bool { 151 | if len(in) != len(bytes32Array) { 152 | return false 153 | } 154 | for i := range bytes32Array { 155 | if !bytes.Equal(bytes32Array[i][:], in[i][:]) { 156 | return false 157 | } 158 | } 159 | return true 160 | } 161 | -------------------------------------------------------------------------------- /test/_corrupt/corrupt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | -------------------------------------------------------------------------------- /test/_counter/contract.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package main 8 | 9 | import ( 10 | "github.com/orbs-network/orbs-contract-sdk/go/sdk/v1" 11 | "github.com/orbs-network/orbs-contract-sdk/go/sdk/v1/events" 12 | "github.com/orbs-network/orbs-contract-sdk/go/sdk/v1/state" 13 | "strconv" 14 | ) 15 | 16 | var PUBLIC = sdk.Export(add, get, start) 17 | var SYSTEM = sdk.Export(_init) 18 | var EVENTS = sdk.Export(Log) 19 | 20 | var COUNTER_KEY = []byte("count") 21 | 22 | func Log(msg string) {} 23 | 24 | func _init() { 25 | state.WriteUint64(COUNTER_KEY, 0) 26 | } 27 | 28 | func add(amount uint64) { 29 | count := state.ReadUint64(COUNTER_KEY) 30 | events.EmitEvent(Log, "previous count is " + strconv.FormatUint(count, 10)) 31 | count += amount 32 | state.WriteUint64(COUNTER_KEY, count) 33 | } 34 | 35 | func get() uint64 { 36 | return state.ReadUint64(COUNTER_KEY) 37 | } 38 | 39 | func start() uint64 { 40 | return 0 41 | } 42 | -------------------------------------------------------------------------------- /test/arguments-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "Arguments", 3 | "MethodName": "check", 4 | "Arguments": [ 5 | { 6 | "Type": "boolArray", 7 | "Value": ["1", "0", "1", "0", "0", "1"] 8 | }, 9 | { 10 | "Type": "uint32Array", 11 | "Value": ["1", "10", "100", "1000", "10000", "100000", "3"] 12 | }, 13 | { 14 | "Type": "uint64Array", 15 | "Value": ["1", "10", "100", "1000", "10000", "100000", "3"] 16 | }, 17 | { 18 | "Type": "uint256Array", 19 | "Value": ["0x0000000000000000000000000000000000000000000000000000000000000001", "0x0000000000000000000000000000000000000000000000000000000000400000"] 20 | }, 21 | { 22 | "Type": "stringArray", 23 | "Value": ["picture", "yourself", "in", "a", "boat", "on", "a", "river"] 24 | }, 25 | { 26 | "Type": "bytesArray", 27 | "Value": ["0x1112", "0x0a0b0c0d", "0x0102"] 28 | }, 29 | { 30 | "Type": "bytes20Array", 31 | "Value": ["0xaabb000000000000000000000000000000000000", "0x0102030102030102030101020301020301020301", "0x0102000000000000000000000000000000000000"] 32 | }, 33 | { 34 | "Type": "bytes32Array", 35 | "Value": ["0x1112000000000000000000000000000000000000000000000000000000000000", "0x0102030102030102030102030102030401020301020301020301020301020304", "0x0a0b0c0d00000000000000000000000000000000000000000000000000000000"] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /test/arguments-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "Arguments", 3 | "MethodName": "get", 4 | "Arguments": [ 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /test/arguments_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "encoding/json" 11 | "github.com/stretchr/testify/require" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func Test_Arguments(t *testing.T) { 17 | cli := GammaCli().WithExperimentalServer().DownloadLatestGammaServer().StartGammaServerAndWait() 18 | defer cli.StopGammaServer() 19 | 20 | outputString, err := cli.Run("deploy", "./_arguments/arguments.go", "-name", "Arguments") 21 | t.Log(outputString) 22 | require.NoError(t, err, "deploy should succeed") 23 | require.True(t, strings.Contains(outputString, `"ExecutionResult": "SUCCESS"`)) 24 | 25 | outputString, err = cli.Run("run-query", "arguments-get.json") 26 | // t.Log(outputString) // uncomment to view output if something change 27 | require.NoError(t, err, "get should succeed") 28 | require.True(t, strings.Contains(outputString, `"ExecutionResult": "SUCCESS"`)) 29 | outputGetParsed := struct { 30 | OutputArguments []*struct { 31 | Type string 32 | Value []string 33 | } 34 | }{} 35 | err = json.Unmarshal([]byte(outputString), &outputGetParsed) 36 | require.NoError(t, err, "parse should succeed") 37 | require.Len(t, outputGetParsed.OutputArguments, 8, "There should be 8 output arrays") 38 | 39 | outputString, err = cli.Run("run-query", "arguments-check.json") 40 | // t.Log(outputString) // uncomment to view output if something change 41 | require.NoError(t, err, "check should succeed") 42 | require.True(t, strings.Contains(outputString, `"ExecutionResult": "SUCCESS"`)) 43 | outputCheckParsed := struct { 44 | OutputArguments []*struct { 45 | Type string 46 | Value string 47 | } 48 | }{} 49 | err = json.Unmarshal([]byte(outputString), &outputCheckParsed) 50 | require.NoError(t, err, "parse should succeed") 51 | require.Len(t, outputCheckParsed.OutputArguments, 2, "There should be 2 output values") 52 | require.Equal(t, "bool", outputCheckParsed.OutputArguments[0].Type) 53 | require.Equal(t, "1", outputCheckParsed.OutputArguments[0].Value) 54 | require.Equal(t, "string", outputCheckParsed.OutputArguments[1].Type) 55 | require.Empty(t, outputCheckParsed.OutputArguments[1].Value) 56 | } 57 | -------------------------------------------------------------------------------- /test/config_override_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/stretchr/testify/require" 5 | "testing" 6 | ) 7 | 8 | func TestGammaCli_StartWithConfigOverrides(t *testing.T) { 9 | cli := GammaCli().WithExperimentalServer().DownloadLatestGammaServer().WithConfigOverrides(`{"virtual-chain-id":43}`).StartGammaServerAndWait() 10 | defer cli.StopGammaServer() 11 | 12 | out, _ := cli.Run("deploy", "./_counter/contract.go", "-name", "CounterExample") 13 | require.Contains(t, out, "REJECTED_VIRTUAL_CHAIN_MISMATCH", "transaction was not rejected when sending a transaction for vcid 42 to a container running vcid 43") 14 | 15 | } 16 | -------------------------------------------------------------------------------- /test/counter-add.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "CounterExample", 3 | "MethodName": "add", 4 | "Arguments": [ 5 | { 6 | "Type": "uint64", 7 | "Value": "25" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /test/counter-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "CounterExample", 3 | "MethodName": "get", 4 | "Arguments": [] 5 | } -------------------------------------------------------------------------------- /test/deploy_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "github.com/stretchr/testify/require" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | func TestDeployCounter(t *testing.T) { 16 | cli := GammaCli().WithExperimentalServer().DownloadLatestGammaServer().StartGammaServerAndWait() 17 | defer cli.StopGammaServer() 18 | 19 | out, err := cli.Run("deploy", "./_counter/contract.go", "-name", "CounterExample") 20 | t.Log(out) 21 | require.NoError(t, err, "deploy should succeed") 22 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 23 | 24 | out, err = cli.Run("run-query", "counter-get.json") 25 | t.Log(out) 26 | require.NoError(t, err, "get should succeed") 27 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 28 | require.True(t, strings.Contains(out, `"Value": "0"`)) 29 | 30 | out, err = cli.Run("send-tx", "counter-add.json") 31 | t.Log(out) 32 | require.NoError(t, err, "add should succeed") 33 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 34 | require.True(t, strings.Contains(out, `"Value": "previous count is 0"`)) 35 | 36 | out, err = cli.Run("run-query", "counter-get.json") 37 | t.Log(out) 38 | require.NoError(t, err, "get should succeed") 39 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 40 | require.True(t, strings.Contains(out, `"Value": "25"`)) 41 | } 42 | 43 | func TestDeployCorruptContract(t *testing.T) { 44 | cli := GammaCli().WithExperimentalServer().DownloadLatestGammaServer().StartGammaServerAndWait() 45 | defer cli.StopGammaServer() 46 | 47 | out, err := cli.Run("deploy", "./_corrupt/corrupt.go", "-name", "CounterExample") 48 | t.Log(out) 49 | require.NoError(t, err, "deploy should succeed") 50 | require.True(t, strings.Contains(out, `"ExecutionResult": "ERROR_SMART_CONTRACT"`)) 51 | require.True(t, strings.Contains(out, `compilation of deployable contract 'CounterExample' failed`)) 52 | } 53 | 54 | func TestDeployOfAlreadyDeployed(t *testing.T) { 55 | cli := GammaCli().WithExperimentalServer().DownloadLatestGammaServer().StartGammaServerAndWait() 56 | defer cli.StopGammaServer() 57 | 58 | out, err := cli.Run("deploy", "./_counter/contract.go", "-name", "CounterExample") 59 | t.Log(out) 60 | require.NoError(t, err, "deploy should succeed") 61 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 62 | 63 | out, err = cli.Run("deploy", "./_counter/contract.go", "-name", "CounterExample") 64 | t.Log(out) 65 | require.NoError(t, err, "deploy should succeed") 66 | require.True(t, strings.Contains(out, `"ExecutionResult": "ERROR_SMART_CONTRACT"`)) 67 | require.True(t, strings.Contains(out, `a contract with same name (case insensitive) already exists`)) 68 | } 69 | 70 | func TestRunMethodWithoutDeploy(t *testing.T) { 71 | cli := GammaCli().WithExperimentalServer().StartGammaServerAndWait() 72 | defer cli.StopGammaServer() 73 | 74 | out, err := cli.Run("send-tx", "counter-add.json") 75 | t.Log(out) 76 | require.NoError(t, err, "add should succeed") 77 | require.True(t, strings.Contains(out, `"RequestStatus": "BAD_REQUEST"`)) 78 | require.True(t, strings.Contains(out, `"ExecutionResult": "ERROR_CONTRACT_NOT_DEPLOYED"`)) 79 | } 80 | -------------------------------------------------------------------------------- /test/generate_config.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 the gamma-cli authors 2 | # This file is part of the gamma-cli library in the Orbs project. 3 | # 4 | # This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | # The above notice should be included in all copies or substantial portions of the software. 6 | 7 | import json 8 | import sys 9 | import socket 10 | 11 | def get_endpoint(ip): 12 | return "http://" + ip + ":8080" 13 | 14 | def get_config(ip): 15 | return { 16 | "Environments": { 17 | "docker": { 18 | "VirtualChain": 42, 19 | "Endpoints": [get_endpoint(ip)] 20 | }, 21 | "docker-experimental": { 22 | "VirtualChain": 42, 23 | "Endpoints": [get_endpoint(ip)], 24 | "Experimental": True 25 | }, 26 | } 27 | } 28 | 29 | if __name__ == "__main__": 30 | ip = socket.gethostbyname(socket.gethostname()) 31 | 32 | if sys.argv[1] == "endpoint": 33 | print get_endpoint(ip) 34 | elif sys.argv[1] == "json": 35 | print json.dumps(get_config(ip)) -------------------------------------------------------------------------------- /test/get-balance.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "BenchmarkToken", 3 | "MethodName": "getBalance", 4 | "Arguments": [ 5 | { 6 | "Type": "gamma:keys-file-address", 7 | "Value": "user2" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /test/harness.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "fmt" 11 | "io/ioutil" 12 | "os" 13 | "os/exec" 14 | "path" 15 | "path/filepath" 16 | "regexp" 17 | "runtime" 18 | "time" 19 | ) 20 | 21 | const CONFIG_FILENAME = "orbs-gamma-config.json" 22 | 23 | var cachedGammaCliBinaryPath string 24 | var downloadedLatestGammaServer bool 25 | 26 | type gammaCli struct { 27 | port string 28 | experimental bool 29 | configOverrides string 30 | prism bool 31 | } 32 | 33 | func compileGammaCli() string { 34 | if gammaCliPathFromEnv := os.Getenv("GAMMA_CLI_PATH"); gammaCliPathFromEnv != "" { 35 | return gammaCliPathFromEnv 36 | } 37 | 38 | if cachedGammaCliBinaryPath != "" { 39 | return cachedGammaCliBinaryPath // cache compilation once per process 40 | } 41 | 42 | tempDir, err := ioutil.TempDir("", "gamma") 43 | if err != nil { 44 | panic(err) 45 | } 46 | 47 | binaryOutputPath := tempDir + "/gamma-cli" 48 | goCmd := path.Join(runtime.GOROOT(), "bin", "go") 49 | cmd := exec.Command(goCmd, "build", "-o", binaryOutputPath, ".") 50 | cmd.Dir = path.Join(getCurrentSourceFileDirPath(), "..") 51 | out, err := cmd.CombinedOutput() 52 | if err != nil { 53 | panic(fmt.Sprintf("compilation failed: %s\noutput:\n%s\n", err.Error(), out)) 54 | } else { 55 | fmt.Printf("compiled gamma-cli successfully:\n %s\n", binaryOutputPath) 56 | } 57 | 58 | cachedGammaCliBinaryPath = binaryOutputPath 59 | return cachedGammaCliBinaryPath 60 | } 61 | 62 | func (g *gammaCli) Run(args ...string) (string, error) { 63 | if len(args) > 0 { 64 | // streamlined supprt for a different port 65 | args = append(args, "-port", g.port) 66 | 67 | // needed for dockerized tests in ci 68 | args = append(args, "-env", g.getGammaEnvironment()) 69 | pathToConfig := path.Join(os.Getenv("HOME"), ".orbs", CONFIG_FILENAME) 70 | args = append(args, "-config", pathToConfig) 71 | 72 | if g.configOverrides != "" { 73 | args = append(args, "-override-config", g.configOverrides) 74 | } 75 | } 76 | out, err := exec.Command(compileGammaCli(), args...).CombinedOutput() 77 | return string(out), err 78 | } 79 | 80 | func GammaCli() *gammaCli { 81 | return GammaCliWithPort(8080) 82 | } 83 | 84 | func GammaCliWithPort(port int) *gammaCli { 85 | return &gammaCli{ 86 | port: fmt.Sprintf("%d", port), 87 | prism: true, 88 | } 89 | } 90 | 91 | func (g *gammaCli) WithConfigOverrides(override string) *gammaCli { 92 | g.configOverrides = override 93 | return g 94 | } 95 | 96 | func (g *gammaCli) WithStableServer() *gammaCli { 97 | g.experimental = false 98 | return g 99 | } 100 | 101 | func (g *gammaCli) WithExperimentalServer() *gammaCli { 102 | g.experimental = true 103 | return g 104 | } 105 | 106 | func (g *gammaCli) WithNoPrism() *gammaCli { 107 | g.prism = false 108 | return g 109 | } 110 | 111 | func (g *gammaCli) StartGammaServerAndWait() *gammaCli { 112 | return g.startInternal(true) 113 | } 114 | 115 | func (g *gammaCli) StartGammaServer() *gammaCli { 116 | return g.startInternal(false) 117 | } 118 | 119 | func (g *gammaCli) startInternal(shouldWait bool) *gammaCli { 120 | commands := []string{"start-local"} 121 | if shouldWait { 122 | commands = append(commands, "-wait") 123 | } 124 | 125 | if !g.prism { 126 | commands = append(commands, "-no-ui") 127 | } 128 | 129 | out, err := g.Run(commands...) 130 | if err != nil { 131 | panic(fmt.Sprintf("start Gamma server failed: %s\noutput:\n%s\n", err.Error(), out)) 132 | } 133 | fmt.Println(out) 134 | return g 135 | } 136 | 137 | func (g *gammaCli) StopGammaServer() { 138 | out, err := g.Run("stop-local") 139 | if err != nil { 140 | panic(fmt.Sprintf("stop Gamma server failed: %s\noutput:\n%s\n", err.Error(), out)) 141 | } 142 | } 143 | 144 | func (g *gammaCli) DownloadLatestGammaServer() *gammaCli { 145 | if downloadedLatestGammaServer { 146 | return g 147 | } 148 | downloadedLatestGammaServer = true 149 | 150 | start := time.Now() 151 | out, err := g.Run("upgrade-server") 152 | if err != nil { 153 | panic(fmt.Sprintf("download latest Gamma server failed: %s\noutput:\n%s\n", err.Error(), out)) 154 | } 155 | delta := time.Now().Sub(start) 156 | fmt.Printf("upgraded gamma-server to latest version (this took %.3fs)\n", delta.Seconds()) 157 | return g 158 | } 159 | 160 | func (g *gammaCli) getGammaEnvironment() string { 161 | if env := os.Getenv("GAMMA_ENVIRONMENT"); env != "" { 162 | if g.experimental { 163 | return env + "-experimental" 164 | } 165 | return env 166 | } 167 | 168 | if g.experimental { 169 | return "experimental" 170 | } 171 | return "local" 172 | } 173 | 174 | func extractTxIdFromSendTxOutput(out string) string { 175 | re := regexp.MustCompile(`\"TxId\":\s+\"(\w+)\"`) 176 | res := re.FindStringSubmatch(out) 177 | return res[1] 178 | } 179 | 180 | func getCurrentSourceFileDirPath() string { 181 | _, filename, _, _ := runtime.Caller(1) 182 | return filepath.Dir(filename) 183 | } 184 | -------------------------------------------------------------------------------- /test/help_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "github.com/stretchr/testify/require" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | func TestHelp(t *testing.T) { 16 | out, err := GammaCli().WithExperimentalServer().Run("help") 17 | t.Log(out) 18 | require.Error(t, err, "help should exit nonzero") 19 | require.NotEmpty(t, out, "help output should not be empty") 20 | require.True(t, strings.Contains(out, "start-local")) 21 | require.True(t, strings.Contains(out, "stop-local")) 22 | 23 | out2, err := GammaCli().WithExperimentalServer().Run() 24 | require.Error(t, err, "run without arguments should exit nonzero") 25 | require.Equal(t, out, out2, "help output should be equal") 26 | } 27 | 28 | func TestVersion(t *testing.T) { 29 | out, err := GammaCli().WithStableServer().Run("version") 30 | t.Log(out) 31 | require.NoError(t, err, "version should succeed") 32 | require.True(t, strings.Contains(out, "Gamma server version")) 33 | require.True(t, strings.Contains(out, "Prism blockchain explorer version")) 34 | require.False(t, strings.Contains(out, `version experimental (docker)`), "started Gamma server should not be experimental") 35 | } 36 | -------------------------------------------------------------------------------- /test/restart_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "github.com/stretchr/testify/require" 11 | "os/exec" 12 | "strings" 13 | "testing" 14 | ) 15 | 16 | func TestRestart(t *testing.T) { 17 | cli := GammaCli().WithStableServer() 18 | defer cli.StopGammaServer() 19 | 20 | out, err := cli.Run("start-local") 21 | t.Log(out) 22 | require.NoError(t, err, "start Gamma server should succeed") 23 | require.False(t, strings.Contains(out, `Orbs Gamma experimental personal blockchain`), "started Gamma server should not be experimental") 24 | require.False(t, strings.Contains(out, `Prism blockchain explorer experimental`), "started Prism server should not be experimental") 25 | 26 | _, err = cli.Run("stop-local") 27 | require.NoError(t, err, "stop Gamma server should succeed") 28 | 29 | _, err = cli.Run("stop-local") 30 | require.NoError(t, err, "second stop Gamma server should succeed") 31 | 32 | _, err = cli.Run("start-local") 33 | require.NoError(t, err, "start Gamma server should succeed") 34 | } 35 | 36 | func TestStopAfterCrashOfGammaServer(t *testing.T) { 37 | cli := GammaCli().WithExperimentalServer() 38 | defer cli.StopGammaServer() 39 | 40 | out, err := cli.Run("start-local") 41 | t.Log(out) 42 | require.NoError(t, err, "start Gamma server should succeed") 43 | require.True(t, strings.Contains(out, `Orbs Gamma personal blockchain experimental`), "started Gamma server should be experimental") 44 | require.True(t, strings.Contains(out, `Prism blockchain explorer experimental`), "started Prism server should be experimental") 45 | 46 | // stopping and removing gamma-server 47 | dockerOut, err := exec.Command("docker", "stop", "orbs-gamma-server").CombinedOutput() 48 | if err != nil { 49 | t.Fatalf("%s", dockerOut) 50 | } 51 | dockerOut, err = exec.Command("docker", "rm", "-f", "orbs-gamma-server").CombinedOutput() 52 | if err != nil { 53 | t.Fatalf("Could not remove docker container.\n\n%s", dockerOut) 54 | } 55 | 56 | // running the regular gamma stop 57 | out, err = cli.Run("stop-local") 58 | require.NoError(t, err, "stop Gamma server should succeed") 59 | require.True(t, strings.Contains(out, "Prism blockchain explorer stopped."), "Prism server should stop even if gamma crashed") 60 | } 61 | -------------------------------------------------------------------------------- /test/token_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "github.com/stretchr/testify/require" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | func TestSimpleTransfer(t *testing.T) { 16 | cli := GammaCli().WithExperimentalServer().DownloadLatestGammaServer().StartGammaServerAndWait() 17 | defer cli.StopGammaServer() 18 | 19 | out, err := cli.Run("run-query", "get-balance.json") 20 | t.Log(out) 21 | require.NoError(t, err, "get balance should not fail (although not deployed)") 22 | require.True(t, strings.Contains(out, `"ExecutionResult": "ERROR_CONTRACT_NOT_DEPLOYED"`)) 23 | 24 | out, err = cli.Run("send-tx", "transfer.json") 25 | t.Log(out) 26 | require.NoError(t, err, "transfer should succeed") 27 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 28 | 29 | txId := extractTxIdFromSendTxOutput(out) 30 | t.Log(txId) 31 | 32 | out, err = cli.Run("tx-status", txId) 33 | t.Log(out) 34 | require.NoError(t, err, "get tx status should succeed") 35 | require.True(t, strings.Contains(out, `"RequestStatus": "COMPLETED"`)) 36 | 37 | out, err = cli.Run("tx-proof", txId) 38 | t.Log(out) 39 | require.NoError(t, err, "get tx proof should succeed") 40 | require.True(t, strings.Contains(out, `"RequestStatus": "COMPLETED"`)) 41 | require.True(t, strings.Contains(out, `"PackedProof": "0x`)) 42 | require.True(t, strings.Contains(out, `"PackedReceipt": "0x`)) 43 | require.True(t, strings.Contains(out, `"ProofSigners": [`)) 44 | require.True(t, strings.Contains(out, `"0xa328846cd5b4979d68a8c58a9bdfeee657b34de7"`)) 45 | 46 | out, err = cli.Run("send-tx", "transfer.json", "-arg1", "2") 47 | t.Log(out) 48 | require.NoError(t, err, "transfer should succeed") 49 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 50 | 51 | out, err = cli.Run("run-query", "get-balance.json") 52 | t.Log(out) 53 | require.NoError(t, err, "get balance should succeed") 54 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 55 | require.True(t, strings.Contains(out, `"Value": "19"`)) 56 | 57 | out, err = cli.Run("send-tx", "transfer-direct.json") 58 | t.Log(out) 59 | require.NoError(t, err, "transfer should succeed") 60 | require.True(t, strings.Contains(out, `"ExecutionResult": "SUCCESS"`)) 61 | } 62 | -------------------------------------------------------------------------------- /test/transfer-direct.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "BenchmarkToken", 3 | "MethodName": "transfer", 4 | "Arguments": [ 5 | { 6 | "Type": "uint64", 7 | "Value": "17" 8 | }, 9 | { 10 | "Type": "bytes", 11 | "Value": "0xb011A26EC85d8B2f9deD3A9062BcbDA4Ed38b778" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /test/transfer.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContractName": "BenchmarkToken", 3 | "MethodName": "transfer", 4 | "Arguments": [ 5 | { 6 | "Type": "uint64", 7 | "Value": "17" 8 | }, 9 | { 10 | "Type": "gamma:keys-file-address", 11 | "Value": "user2" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /test/upgrade_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 the gamma-cli authors 2 | // This file is part of the gamma-cli library in the Orbs project. 3 | // 4 | // This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. 5 | // The above notice should be included in all copies or substantial portions of the software. 6 | 7 | package test 8 | 9 | import ( 10 | "fmt" 11 | "github.com/stretchr/testify/require" 12 | "os/exec" 13 | "regexp" 14 | "strings" 15 | "testing" 16 | ) 17 | 18 | func TestUpgradeStableServer(t *testing.T) { 19 | cli := GammaCli().WithStableServer() 20 | 21 | out, err := cli.Run("version") 22 | t.Log(out) 23 | require.NoError(t, err, "version should succeed") 24 | require.True(t, strings.Contains(out, `(docker)`), "version output should show docker") 25 | 26 | out, err = cli.Run("upgrade-server") 27 | t.Log(out) 28 | require.NoError(t, err, "upgrade server stable should succeed") 29 | require.True(t, strings.Contains(out, `does not require upgrade`), "upgrade same tag should not try to pull fresh copy") 30 | require.True(t, strings.Contains(out, `Current Orbs Gamma`), "upgrade worked on gamma-server") 31 | require.True(t, strings.Contains(out, `Current Prism`), "upgrade worked on prism") 32 | } 33 | 34 | func TestUpgradeExperimentalServer(t *testing.T) { 35 | cli := GammaCli().WithExperimentalServer() 36 | defer cli.StopGammaServer() 37 | 38 | out, err := cli.Run("version") 39 | t.Log(out) 40 | require.NoError(t, err, "version experimental should succeed") 41 | require.True(t, strings.Contains(out, `experimental (docker)`), "version output should show experimental docker") 42 | 43 | out, err = cli.Run("upgrade-server") 44 | t.Log(out) 45 | require.NoError(t, err, "upgrade server experimental should succeed") 46 | require.True(t, strings.Contains(out, `experimental: Pulling from orbsnetwork/gamma`), "experimental upgrade should always try to pull fresh copy (gamma)") 47 | require.True(t, strings.Contains(out, `experimental: Pulling from orbsnetwork/prism`), "experimental upgrade should always try to pull fresh copy (prism)") 48 | 49 | out, err = cli.Run("start-local") 50 | t.Log(out) 51 | require.NoError(t, err, "start Gamma server should succeed") 52 | require.True(t, strings.Contains(out, `Orbs Gamma personal blockchain experimental`), "started Gamma server should be experimental") 53 | require.True(t, strings.Contains(out, `Prism blockchain explorer experimental`), "started Prism server should be experimental") 54 | } 55 | 56 | func TestStableServerDoesNotRestartWhenVersionUpgradeNotRequired(t *testing.T) { 57 | cli := GammaCli().WithStableServer() 58 | defer cli.StopGammaServer() 59 | 60 | out, err := cli.Run("version") 61 | t.Log(out) 62 | require.NoError(t, err, "version should succeed") 63 | require.True(t, strings.Contains(out, `(docker)`), "version output should show docker") 64 | 65 | out, err = cli.Run("start-local") 66 | require.NoError(t, err, "start Gamma server should succeed") 67 | 68 | out, err = cli.Run("upgrade-server") 69 | require.NoError(t, err, "upgrade server stable should succeed") 70 | require.True(t, strings.Contains(out, `does not require upgrade`), "upgrade same tag should not try to pull fresh copy") 71 | require.True(t, strings.Contains(out, `Current Orbs Gamma`), "upgrade worked on gamma-server") 72 | require.True(t, strings.Contains(out, `Current Prism`), "upgrade worked on prism") 73 | require.False(t, strings.Contains(out, "Orbs Gamma personal blockchain stopped."), "Gamma should not restart if no upgrade happened") 74 | require.False(t, strings.Contains(out, "Prism blockchain explorer stopped."), "Prism should not restart if no upgrade happened") 75 | } 76 | 77 | func TestExperimentalServerDoesNotRestartWhenVersionUpgradeNotRequired(t *testing.T) { 78 | cli := GammaCli().WithExperimentalServer() 79 | defer cli.StopGammaServer() 80 | 81 | out, err := cli.Run("version") 82 | t.Log(out) 83 | require.NoError(t, err, "version should succeed") 84 | require.True(t, strings.Contains(out, `(docker)`), "version output should show docker") 85 | 86 | out, err = cli.Run("start-local") 87 | require.NoError(t, err, "start Gamma server should succeed") 88 | 89 | out, err = cli.Run("upgrade-server") 90 | require.NoError(t, err, "upgrade server stable should succeed") 91 | require.True(t, strings.Contains(out, `Image is up to date`), "re-upgrade experimental should not try to pull fresh copy") 92 | require.False(t, strings.Contains(out, "Orbs Gamma personal blockchain stopped."), "Gamma should not restart if no upgrade happened") 93 | require.False(t, strings.Contains(out, "Prism blockchain explorer stopped."), "Prism should not restart if no upgrade happened") 94 | } 95 | 96 | func TestPrismNotRestartedOnUpgradeRestartWhenNotRunningBefore(t *testing.T) { 97 | // can only test this with stable, because of how docker/gamma automation works 98 | cli := GammaCli().WithStableServer().WithNoPrism() 99 | defer cli.StopGammaServer() 100 | 101 | out, err := cli.Run("version") 102 | t.Log(out) 103 | require.NoError(t, err, "version should succeed") 104 | require.True(t, strings.Contains(out, `(docker)`), "version output should show docker") 105 | 106 | // get an old version 107 | dockerOut, err := exec.Command("docker", "pull", "orbsnetwork/gamma:v1.1.1").CombinedOutput() 108 | if err != nil { 109 | t.Fatalf("%s", dockerOut) 110 | } 111 | 112 | // get latest tag and remove it (so upgrade will happen) 113 | pattern := fmt.Sprintf(`%s\s+(v\S+)`, regexp.QuoteMeta("Gamma server version")) 114 | re := regexp.MustCompile(pattern) 115 | res := re.FindStringSubmatch(out) 116 | dockerOut, err = exec.Command("docker", "rmi", "orbsnetwork/gamma:"+res[1]).CombinedOutput() 117 | if err != nil { 118 | t.Fatalf("%s", dockerOut) 119 | } 120 | 121 | cli = cli.StartGammaServerAndWait() 122 | 123 | out, err = cli.Run("upgrade-server") 124 | t.Log(out) 125 | require.NoError(t, err, "upgrade server stable should succeed") 126 | require.True(t, strings.Contains(out, `Downloading latest`), "we are forcing an upgrade, it should download something") 127 | require.True(t, strings.Contains(out, "Orbs Gamma personal blockchain stopped."), "Gamma was upgraded and needs to restart") 128 | require.False(t, strings.Contains(out, "Prism blockchain explorer stopped."), "Prism should not restart as it was not running before") 129 | } --------------------------------------------------------------------------------