{"id":36548149,"url":"https://github.com/chainhero/heroes-service","last_synced_at":"2026-01-15T02:45:26.978Z","repository":{"id":47472529,"uuid":"96316970","full_name":"chainHero/heroes-service","owner":"chainHero","description":"Short tutorial to build a blockchain application in Go with Hyperledger Fabric","archived":false,"fork":false,"pushed_at":"2021-12-17T09:51:59.000Z","size":8670,"stargazers_count":276,"open_issues_count":20,"forks_count":145,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-15T10:42:48.885Z","etag":null,"topics":["blockchain","golang","hyperledger","hyperledger-fabric","tutorial"],"latest_commit_sha":null,"homepage":"https://chainhero.io/2018/06/tutorial-build-blockchain-app-v1-1-0/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chainHero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-05T12:31:07.000Z","updated_at":"2025-04-12T03:47:51.000Z","dependencies_parsed_at":"2022-09-01T22:31:13.607Z","dependency_job_id":null,"html_url":"https://github.com/chainHero/heroes-service","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chainHero/heroes-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainHero%2Fheroes-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainHero%2Fheroes-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainHero%2Fheroes-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainHero%2Fheroes-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chainHero","download_url":"https://codeload.github.com/chainHero/heroes-service/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chainHero%2Fheroes-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28441438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T00:55:22.719Z","status":"online","status_checked_at":"2026-01-15T02:00:08.019Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","golang","hyperledger","hyperledger-fabric","tutorial"],"created_at":"2026-01-12T06:14:59.539Z","updated_at":"2026-01-15T02:45:26.971Z","avatar_url":"https://github.com/chainHero.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tutorial Hyperledger Fabric SDK Go: How to build your first app?\n\nSource: [chainhero.io/2018/06/tutorial-build-blockchain-app-v1-1-0](https://chainhero.io/2018/06/tutorial-build-blockchain-app-v1-1-0/)\n\nThis tutorial will introduce you to the Hyperledger Fabric Go SDK and allows you to build a simple application using the blockchain principle.\n\n**This tutorial uses Hyperledger Fabric version 1.1.0**\n\nThis is the **first part** of this tutorial. The basics SDK features will be shown, but the second part is scheduled to demonstrate a more complex application.\n\n## 1. Prerequisites\n\nThis tutorial won’t explain in detail how Hyperledger Fabric works. I will just give some tips to understand the general behavior of the framework. If you want to get a full explanation of the tool, go to the official [documentation](http://hyperledger-fabric.readthedocs.io/en/latest/) there is a lot of work there that explains what kind of blockchain Hyperledger Fabric is.\n\nThis tutorial has been made on **Ubuntu 16.04** but the Hyperledger Fabric framework is compatible with Mac OS X, Windows and other Linux distributions.\n\nWe will use the **Go** language to design our first application because the Hyperledger Fabric has been also built in Go and the Fabric SDK Go is really simple to use. In addition, the chaincode (smart contract) can be written in Go too. So the full-stack will be only in Go! Awesome right ? However, if you are go phobic, there are other SDK like for NodeJS, Java or Python but we won't discuss about them here.\n\nHyperledger Fabric uses **Docker** to easily deploy a blockchain network. In addition, some components (peers) also deploys docker containers to separate data (channel). So make sure that your platform supports this kind of virtualization.\n\n## 2. Introduction to Hyperledger Fabric\n\n\u003e Hyperledger Fabric is a platform for distributed ledger solutions underpinned by a modular architecture delivering high degrees of confidentiality, resiliency, flexibility and scalability. It is designed to support pluggable implementations of different components and accommodate the complexity and intricacies that exist across the economic ecosystem.\n\nSee the full explanation from the official documentation in the introduction part: [Hyperledger Fabric Blockchain](http://hyperledger-fabric.readthedocs.io/en/latest/blockchain.html)\n\n![Blockchain Concensus](http://hyperledger-fabric.readthedocs.io/en/latest/_images/consensus.png)\n\n## 3. Installation guide\n\nThis tutorial was made on **Ubuntu 16.04**, but there is help for Windows, Mac OS X and other Linux distributions users.\n\n### a. Docker\n\n**Docker version 17.03.0-ce or greater is required.**\n\n#### Linux (Ubuntu)\n\nFirst of all, in order to install docker correctly we need to install its dependencies:\n\n```bash\nsudo apt install apt-transport-https ca-certificates curl software-properties-common\n```\n\nOnce the dependencies are installed, we can install docker:\n\n```bash\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - \u0026\u0026 \\\nsudo add-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" \u0026\u0026 \\\nsudo apt update \u0026\u0026 \\\nsudo apt install -y docker-ce\n```\n\nNow we need to manage the current user to avoid using administration rights (`root`) access when we will use the docker command. To do so, we need to add the current user to the `docker` group:\n\n```bash\nsudo groupadd docker ; \\\nsudo gpasswd -a ${USER} docker \u0026\u0026 \\\nsudo service docker restart\n```\n\nDo not mind if `groupadd: group 'docker' already exists` error pop up.\n\nTo apply the changes made, you need to logout/login. You can then check your version with:\n\n```bash\ndocker -v\n```\n\n![End of the docker installation](docs/images/finish-docker-install.png)\n\n#### Mac OS X\n\nDownload and install the latest [`Docker.dmg`](https://docs.docker.com/docker-for-mac/install/) package for Mac OS X available on the [Docker](https://docs.docker.com/docker-for-mac/install/) website. This will install `docker-compose` as well, so you can skip the next step.\n\n#### Linux (not Ubuntu)\n\nSee links below:\n- [Debian](https://docs.docker.com/engine/installation/linux/docker-ce/debian/)\n- [Fedora](https://docs.docker.com/engine/installation/linux/docker-ce/fedora/)\n- [CentOS](https://docs.docker.com/engine/installation/linux/docker-ce/centos/)\n\n#### Windows\n\nSee instructions from the Docker website: [docker.com/docker-for-windows](https://docs.docker.com/docker-for-windows/install/)\n\n### b. Docker Compose\n\n**Docker-compose version 1.8 or greater is required.**\n\nWe are currently unable to manage easily multiple containers at once. To solve this issue, we need **docker-compose**.\n\n#### Linux\n\nThe installation is pretty fast:\n\n```bash\nsudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose \u0026\u0026 \\\nsudo chmod +x /usr/local/bin/docker-compose\n```\n\nApply these changes by logout/login and then check its version with:\n\n```bash\ndocker-compose version\n```\n\n![End of the docker compose installation](docs/images/finish-docker_compose-install.png)\n\n#### Windows / Others\n\nSee instructions from the Docker-compose website: [docs.docker.com/compose/install](https://docs.docker.com/compose/install/)\n\n### c. Go\n\n**Go version 1.9.x or greater is required.**\n\n#### Linux\n\nYou can either follow instructions from [golang.org](https://golang.org/dl/) or use those generics commands that will install Golang 1.9.2 and prepare your environment (generate your `GOPATH`) for Ubuntu:\n\n```bash\nwget https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz \u0026\u0026 \\\nsudo tar -C /usr/local -xzf go1.9.2.linux-amd64.tar.gz \u0026\u0026 \\\nrm go1.9.2.linux-amd64.tar.gz \u0026\u0026 \\\necho 'export PATH=$PATH:/usr/local/go/bin' | sudo tee -a /etc/profile \u0026\u0026 \\\necho 'export GOPATH=$HOME/go' | tee -a $HOME/.bashrc \u0026\u0026 \\\necho 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' | tee -a $HOME/.bashrc \u0026\u0026 \\\nmkdir -p $HOME/go/{src,pkg,bin}\n```\n\nTo make sure that the installation works, you can logout/login (again) and run:\n\n```bash\ngo version\n```\n\n![End of the go installation](docs/images/finish-go-install.png)\n\n\n#### Windows / Mac OS X / Others\n\nSee instructions from the Golang website: [golang.org/install](https://golang.org/doc/install)\n\n## 4. Make your first blockchain network\n\n### a. Prepare environment\n\nIn order to make a blockchain network, we will use `docker` to build virtual computers that will handle different roles. In this tutorial we will stay as simple as possible. Hyperledger Fabric needs a lot of certificates to ensure encryption during the whole end to end process (TSL, authentications, signing blocks...). The creation of these files requires a little time and in order to go straight to the heart of the matter, we have already prepared all this for you in the folder `fixtures` in this repository.\n\nMake a new directory in the `src` folder of your `GOPATH`, following our repository naming:\n\n```bash\nmkdir -p $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\ncd $GOPATH/src/github.com/chainHero/heroes-service\n```\n\nTo get the `fixtures` folder, you can either follow this command line, which will install and use subversion to get the folder from this repository. Or download the [zip file from Github](https://github.com/chainHero/heroes-service/archive/v1.1.0.zip) and extract only the `fixtures` folder.\n\n```bash\nsudo apt install -y subversion \u0026\u0026 \\\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nsvn checkout https://github.com/chainHero/heroes-service/branches/v1.1.0/fixtures \u0026\u0026\nrm -rf fixtures/.svn\n```\n\nAlternatively, if you want to know how to build this fixture folder and learn how to create the blockchain network, follow this quick tutorial on [how to build your first network](https://chainhero.io/2018/04/tutorial-hyperledger-fabric-how-to-build-your-first-network/).\n\n### b. Test\n\nIn order to check if the network works, we will use `docker-compose` to start or stop all containers at the same time. Go inside the `fixtures` folder, and run:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service/fixtures \u0026\u0026 \\\ndocker-compose up\n```\n\nYou will see a lot of logs with different colors (for your information, red isn't equal to errors).\n\nOpen a new terminal and run:\n\n```bash\ndocker ps\n```\n\n![Docker compose up screenshot](docs/images/docker-ps.png)\n\nYou will see : two peers, the orderer and one CA containers. You have successfully made a new network ready to use with the SDK. To stop the network go back to the previous terminal, press `Ctrl+C` and wait that all containers are stopped. If you want to explore more deeper, follow our tutorial dedicated to the network part [here](https://chainhero.io/2018/04/tutorial-hyperledger-fabric-how-to-build-your-first-network/) or  check out the official documentation about this: [Building Your First Network](http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html)\n\n\u003e **Tips**: when the network is stopped, all containers used remain accessible. This is very useful to check logs for example. You can see stopped containers with `docker ps -a`. In order to clean up these containers, you need to delete them with `docker rm $(docker ps -aq)` or if you have used a `docker-compose` file, go where this file is and run `docker-compose down`.\n\n\u003e **Tips**: you can run the `docker-compose` command in background to keep the prompt. To do so, use the parameter `-d`, like this: `docker-compose up -d`. To stop containers, place yourself in the same folder where the `docker-compose.yaml` is and run : `docker-compose stop` (or `docker-compose down` to additionally clean up all containers when they are stopped).\n\n\n## 5. Use the Fabric SDK Go\n\n### a. Configuration\n\nOur application needs a lot of parameters, especially the addresses of the Fabric's components to communicate. We will put everything in a new configuration file, the Fabric SDK Go configuration and our custom parameters. For the moment, we will only try to make the Fabric SDK Go works with the default chaincode:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi config.yaml\n```\n\n```yaml\nname: \"heroes-service-network\"\n#\n# Schema version of the content. Used by the SDK to apply the corresponding parsing rules.\n#\nversion: 1.0.0\n\n#\n# The client section used by GO SDK.\n#\nclient:\n\n  # Which organization does this application instance belong to? The value must be the name of an org\n  # defined under \"organizations\"\n  organization: org1\n\n  logging:\n    level: info\n\n  # Global configuration for peer, event service and orderer timeouts\n  # if this this section is omitted, then default values will be used (same values as below)\n#  peer:\n#    timeout:\n#      connection: 10s\n#      response: 180s\n#      discovery:\n#        # Expiry period for discovery service greylist filter\n#        # The channel client will greylist peers that are found to be offline\n#        # to prevent re-selecting them in subsequent retries.\n#        # This interval will define how long a peer is greylisted\n#        greylistExpiry: 10s\n#  eventService:\n#    # Event service type (optional). If not specified then the type is automatically\n#    # determined from channel capabilities.\n#    type: (deliver|eventhub)\n    # the below timeouts are commented out to use the default values that are found in\n    # \"pkg/fab/endpointconfig.go\"\n    # the client is free to override the default values by uncommenting and resetting\n    # the values as they see fit in their config file\n#    timeout:\n#      connection: 15s\n#      registrationResponse: 15s\n#  orderer:\n#    timeout:\n#      connection: 15s\n#      response: 15s\n#  global:\n#    timeout:\n#      query: 180s\n#      execute: 180s\n#      resmgmt: 180s\n#    cache:\n#      connectionIdle: 30s\n#      eventServiceIdle: 2m\n#      channelConfig: 30m\n#      channelMembership: 30s\n#      discovery: 10s\n#      selection: 10m\n\n  # Root of the MSP directories with keys and certs.\n  cryptoconfig:\n    path: ${GOPATH}/src/github.com/chainHero/heroes-service/fixtures/crypto-config\n\n  # Some SDKs support pluggable KV stores, the properties under \"credentialStore\"\n  # are implementation specific\n  credentialStore:\n    path: /tmp/heroes-service-store\n\n    # [Optional]. Specific to the CryptoSuite implementation used by GO SDK. Software-based implementations\n    # requiring a key store. PKCS#11 based implementations does not.\n    cryptoStore:\n      path: /tmp/heroes-service-msp\n\n   # BCCSP config for the client. Used by GO SDK.\n  BCCSP:\n    security:\n     enabled: true\n     default:\n      provider: \"SW\"\n     hashAlgorithm: \"SHA2\"\n     softVerify: true\n     level: 256\n\n  tlsCerts:\n    # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false\n    systemCertPool: false\n\n    # [Optional]. Client key and cert for TLS handshake with peers and orderers\n    client:\n      keyfile:\n      certfile:\n\n#\n# [Optional]. But most apps would have this section so that channel objects can be constructed\n# based on the content below. If an app is creating channels, then it likely will not need this\n# section.\n#\nchannels:\n  # name of the channel\n  chainhero:\n    # Required. list of orderers designated by the application to use for transactions on this\n    # channel. This list can be a result of access control (\"org1\" can only access \"ordererA\"), or\n    # operational decisions to share loads from applications among the orderers.  The values must\n    # be \"names\" of orgs defined under \"organizations/peers\"\n    # deprecated: not recommended, to override any orderer configuration items, entity matchers should be used.\n    # orderers:\n    #  - orderer.example.com\n\n    # Required. list of peers from participating orgs\n    peers:\n      peer0.org1.hf.chainhero.io:\n        # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must\n        # have the chaincode installed. The app can also use this property to decide which peers\n        # to send the chaincode install request. Default: true\n        endorsingPeer: true\n\n        # [Optional]. will this peer be sent query proposals? The peer must have the chaincode\n        # installed. The app can also use this property to decide which peers to send the\n        # chaincode install request. Default: true\n        chaincodeQuery: true\n\n        # [Optional]. will this peer be sent query proposals that do not require chaincodes, like\n        # queryBlock(), queryTransaction(), etc. Default: true\n        ledgerQuery: true\n\n        # [Optional]. will this peer be the target of the SDK's listener registration? All peers can\n        # produce events but the app typically only needs to connect to one to listen to events.\n        # Default: true\n        eventSource: true\n\n      peer1.org1.hf.chainhero.io:\n\n    policies:\n      #[Optional] options for retrieving channel configuration blocks\n      queryChannelConfig:\n        #[Optional] min number of success responses (from targets/peers)\n        minResponses: 1\n        #[Optional] channel config will be retrieved for these number of random targets\n        maxTargets: 1\n        #[Optional] retry options for query config block\n        retryOpts:\n          #[Optional] number of retry attempts\n          attempts: 5\n          #[Optional] the back off interval for the first retry attempt\n          initialBackoff: 500ms\n          #[Optional] the maximum back off interval for any retry attempt\n          maxBackoff: 5s\n          #[Optional] he factor by which the initial back off period is exponentially incremented\n          backoffFactor: 2.0\n\n\n#\n# list of participating organizations in this network\n#\norganizations:\n  org1:\n    mspid: org1.hf.chainhero.io\n    cryptoPath: peerOrganizations/org1.hf.chainhero.io/users/{userName}@org1.hf.chainhero.io/msp\n    peers:\n      - peer0.org1.hf.chainhero.io\n      - peer1.org1.hf.chainhero.io\n\n    # [Optional]. Certificate Authorities issue certificates for identification purposes in a Fabric based\n    # network. Typically certificates provisioning is done in a separate process outside of the\n    # runtime network. Fabric-CA is a special certificate authority that provides a REST APIs for\n    # dynamic certificate management (enroll, revoke, re-enroll). The following section is only for\n    # Fabric-CA servers.\n    certificateAuthorities:\n      - ca.org1.hf.chainhero.io\n\n#\n# List of orderers to send transaction and channel create/update requests to. For the time\n# being only one orderer is needed. If more than one is defined, which one get used by the\n# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers.\n#\norderers:\n  orderer.hf.chainhero.io:\n    url: localhost:7050\n\n    # these are standard properties defined by the gRPC library\n    # they will be passed in as-is to gRPC client constructor\n    grpcOptions:\n      ssl-target-name-override: orderer.hf.chainhero.io\n      # These parameters should be set in coordination with the keepalive policy on the server,\n      # as incompatible settings can result in closing of connection.\n      # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled\n      keep-alive-time: 0s\n      keep-alive-timeout: 20s\n      keep-alive-permit: false\n      fail-fast: false\n      # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs\n      allow-insecure: false\n\n    tlsCACerts:\n      # Certificate location absolute path\n      path: ${GOPATH}/src/github.com/chainHero/heroes-service/fixtures/crypto-config/ordererOrganizations/hf.chainhero.io/tlsca/tlsca.hf.chainhero.io-cert.pem\n#\n# List of peers to send various requests to, including endorsement, query\n# and event listener registration.\n#\npeers:\n  peer0.org1.hf.chainhero.io:\n    # this URL is used to send endorsement and query requests\n    url: localhost:7051\n    # eventUrl is only needed when using eventhub (default is delivery service)\n    eventUrl: localhost:7053\n\n    grpcOptions:\n      ssl-target-name-override: peer0.org1.hf.chainhero.io\n      # These parameters should be set in coordination with the keepalive policy on the server,\n      # as incompatible settings can result in closing of connection.\n      # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled\n      keep-alive-time: 0s\n      keep-alive-timeout: 20s\n      keep-alive-permit: false\n      fail-fast: false\n      # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs\n      allow-insecure: false\n\n    tlsCACerts:\n      # Certificate location absolute path\n      path: ${GOPATH}/src/github.com/chainHero/heroes-service/fixtures/crypto-config/peerOrganizations/org1.hf.chainhero.io/tlsca/tlsca.org1.hf.chainhero.io-cert.pem\n\n  peer1.org1.hf.chainhero.io:\n    # this URL is used to send endorsement and query requests\n    url: localhost:8051\n    # eventUrl is only needed when using eventhub (default is delivery service)\n    eventUrl: localhost:8053\n\n    grpcOptions:\n      ssl-target-name-override: peer1.org1.hf.chainhero.io\n      # These parameters should be set in coordination with the keepalive policy on the server,\n      # as incompatible settings can result in closing of connection.\n      # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled\n      keep-alive-time: 0s\n      keep-alive-timeout: 20s\n      keep-alive-permit: false\n      fail-fast: false\n      # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs\n      allow-insecure: false\n\n    tlsCACerts:\n      # Certificate location absolute path\n      path: ${GOPATH}/src/github.com/chainHero/heroes-service/fixtures/crypto-config/peerOrganizations/org1.hf.chainhero.io/tlsca/tlsca.org1.hf.chainhero.io-cert.pem\n\n#\n# Fabric-CA is a special kind of Certificate Authority provided by Hyperledger Fabric which allows\n# certificate management to be done via REST APIs. Application may choose to use a standard\n# Certificate Authority instead of Fabric-CA, in which case this section would not be specified.\n#\ncertificateAuthorities:\n  ca.org1.hf.chainhero.io:\n    url: http://localhost:7054\n    # Fabric-CA supports dynamic user enrollment via REST APIs. A \"root\" user, a.k.a registrar, is\n    # needed to enroll and invoke new users.\n    httpOptions:\n      verify: false\n    registrar:\n      enrollId: admin\n      enrollSecret: adminpw\n    # [Optional] The optional name of the CA.\n    caName: ca.org1.hf.chainhero.io\n    tlsCACerts:\n      # Certificate location absolute path\n      path: ${GOPATH}/src/github.com/chainHero/heroes-service/fixtures/crypto-config/peerOrganizations/org1.hf.chainhero.io/ca/ca.org1.hf.chainhero.io-cert.pem\n\nentityMatchers:\n  peer:\n    - pattern: (\\w*)peer0.org1.hf.chainhero.io(\\w*)\n      urlSubstitutionExp: localhost:7051\n      eventUrlSubstitutionExp: localhost:7053\n      sslTargetOverrideUrlSubstitutionExp: peer0.org1.hf.chainhero.io\n      mappedHost: peer0.org1.hf.chainhero.io\n\n    - pattern: (\\w*)peer1.org1.hf.chainhero.io(\\w*)\n      urlSubstitutionExp: localhost:8051\n      eventUrlSubstitutionExp: localhost:8053\n      sslTargetOverrideUrlSubstitutionExp: peer1.org1.hf.chainhero.io\n      mappedHost: peer1.org1.hf.chainhero.io\n\n  orderer:\n    - pattern: (\\w*)orderer.hf.chainhero.io(\\w*)\n      urlSubstitutionExp: localhost:7050\n      sslTargetOverrideUrlSubstitutionExp: orderer.hf.chainhero.io\n      mappedHost: orderer.hf.chainhero.io\n\n  certificateAuthorities:\n    - pattern: (\\w*)ca.org1.hf.chainhero.io(\\w*)\n      urlSubstitutionExp: http://localhost:7054\n      mappedHost: ca.org1.hf.chainhero.io\n```\n\nThe configuration file is also available here: [`config.yaml`](config.yaml)\n\n### b. Initialise\n\nWe add a new folder named `blockchain` that will contain the whole interface that communicate with the network. We will see the Fabric SDK Go only in this folder.\n\n```bash\nmkdir $GOPATH/src/github.com/chainHero/heroes-service/blockchain\n```\n\nNow, we add a new go file named `setup.go` :\n\n```bash\nvi $GOPATH/src/github.com/chainHero/heroes-service/blockchain/setup.go\n```\n\n```go\npackage blockchain\n\nimport (\n\t\"fmt\"\n\tmspclient \"github.com/hyperledger/fabric-sdk-go/pkg/client/msp\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/core/config\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk\"\n\t\"github.com/pkg/errors\"\n)\n\n// FabricSetup implementation\ntype FabricSetup struct {\n\tConfigFile      string\n\tOrgID           string\n\tOrdererID\tstring\n\tChannelID       string\n\tChainCodeID     string\n\tinitialized     bool\n\tChannelConfig   string\n\tChaincodeGoPath string\n\tChaincodePath   string\n\tOrgAdmin        string\n\tOrgName         string\n\tUserName        string\n\tadmin           *resmgmt.Client\n\tsdk             *fabsdk.FabricSDK\n}\n\n// Initialize reads the configuration file and sets up the client, chain and event hub\nfunc (setup *FabricSetup) Initialize() error {\n\n\t// Add parameters for the initialization\n\tif setup.initialized {\n\t\treturn errors.New(\"sdk already initialized\")\n\t}\n\n\t// Initialize the SDK with the configuration file\n\tsdk, err := fabsdk.New(config.FromFile(setup.ConfigFile))\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create SDK\")\n\t}\n\tsetup.sdk = sdk\n\tfmt.Println(\"SDK created\")\n\n\t// The resource management client is responsible for managing channels (create/update channel)\n\tresourceManagerClientContext := setup.sdk.Context(fabsdk.WithUser(setup.OrgAdmin), fabsdk.WithOrg(setup.OrgName))\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to load Admin identity\")\n\t}\n\tresMgmtClient, err := resmgmt.New(resourceManagerClientContext)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create channel management client from Admin identity\")\n\t}\n\tsetup.admin = resMgmtClient\n\tfmt.Println(\"Ressource management client created\")\n\n\t// The MSP client allow us to retrieve user information from their identity, like its signing identity which we will need to save the channel\n\tmspClient, err := mspclient.New(sdk.Context(), mspclient.WithOrg(setup.OrgName))\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create MSP client\")\n\t}\n\tadminIdentity, err := mspClient.GetSigningIdentity(setup.OrgAdmin)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to get admin signing identity\")\n\t}\n\treq := resmgmt.SaveChannelRequest{ChannelID: setup.ChannelID, ChannelConfigPath: setup.ChannelConfig, SigningIdentities: []msp.SigningIdentity{adminIdentity}}\n\ttxID, err := setup.admin.SaveChannel(req, resmgmt.WithOrdererEndpoint(setup.OrdererID))\n\tif err != nil || txID.TransactionID == \"\" {\n\t\treturn errors.WithMessage(err, \"failed to save channel\")\n\t}\n\tfmt.Println(\"Channel created\")\n\n\t// Make admin user join the previously created channel\n\tif err = setup.admin.JoinChannel(setup.ChannelID, resmgmt.WithRetry(retry.DefaultResMgmtOpts), resmgmt.WithOrdererEndpoint(setup.OrdererID)); err != nil {\n\t\treturn errors.WithMessage(err, \"failed to make admin join channel\")\n\t}\n\tfmt.Println(\"Channel joined\")\n\n\tfmt.Println(\"Initialization Successful\")\n\tsetup.initialized = true\n\treturn nil\n}\n\nfunc (setup *FabricSetup) CloseSDK() {\n\tsetup.sdk.Close()\n}\n\n```\n\nThe file is available here: [`blockchain/setup.go`](blockchain/setup.go)\n\nAt this stage, we only initialized a client that will communicate to a peer, a CA and an orderer. We also made a new channel and connected this peer to this channel. See the comments in the code for more information.\n\n### c. Test\n\nTo make sure that the client managed to initialize all his components, we will make a simple test with the network launched. In order to do this, we need to build the go code. Since we we haven't any main file we have to add one:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi main.go\n```\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/chainHero/heroes-service/blockchain\"\n\t\"os\"\n)\n\nfunc main() {\n\t// Definition of the Fabric SDK properties\n\tfSetup := blockchain.FabricSetup{\n\t\t// Network parameters \n\t\tOrdererID: \"orderer.hf.chainhero.io\",\n\n\t\t// Channel parameters\n\t\tChannelID:     \"chainhero\",\n\t\tChannelConfig: os.Getenv(\"GOPATH\") + \"/src/github.com/chainHero/heroes-service/fixtures/artifacts/chainhero.channel.tx\",\n\n\t\t// Chaincode parameters\n\t\tChainCodeID:     \"heroes-service\",\n\t\tChaincodeGoPath: os.Getenv(\"GOPATH\"),\n\t\tChaincodePath:   \"github.com/chainHero/heroes-service/chaincode/\",\n\t\tOrgAdmin:        \"Admin\",\n\t\tOrgName:         \"org1\",\n\t\tConfigFile:      \"config.yaml\",\n\n\t\t// User parameters\n\t\tUserName: \"User1\",\n\t}\n\n\t// Initialization of the Fabric SDK from the previously set properties\n\terr := fSetup.Initialize()\n\tif err != nil {\n\t\tfmt.Printf(\"Unable to initialize the Fabric SDK: %v\\n\", err)\n\t\treturn\n\t}\n\t// Close SDK\n\tdefer fSetup.CloseSDK()\t\n}\n```\n\nThe file is available here: [`main.go`](main.go)\n\nThe last thing to do, before starting the compilation, is to use a vendor directory that will contain all our dependencies. In our GOPATH we have Fabric SDK Go and maybe other projects. When we will try to compile our app, Golang search dependencies in our GOPATH, but first it checks if there is a vendor folder in the project. If the dependency is satisfied, then Golang doesn't go looking in GOPATH or GOROOT. This is very useful when using several different versions of a dependency (some conflicts can happen, like multiple definitions of BCCSP in our case. We will handle this by using a tool like [`dep`](https://github.com/golang/dep) to flatten these dependencies in the `vendor` directory.\n\nWhen you installed the SDK dependencies, DEP was automatically installed. If this is not the case, you can install it by reading the instructions available here: [dep installation](https://github.com/golang/dep#installation)\n\nCreate a file called `Gopkg.toml` and copy this inside:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi Gopkg.toml\n```\n\n```toml\nignored = [\"github.com/chainHero/heroes-service/chaincode\"]\n\n[[constraint]]\n  # Release v1.0.0-alpha4\n  name = \"github.com/hyperledger/fabric-sdk-go\"\n  revision = \"a906355f73d060d7bf95874a9e90dc17589edbb3\"\n\n```\n\nThis is a constraint for `dep` in order to specify that in our vendor we want the SDK Go to a specific version.\n\nSave the file and then execute this command to synchronize the vendor directory with our project's dependencies (this may take a while to proceed):\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\ndep ensure\n```\n\nNow we can compile our application:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\ngo build\n```\n\nAfter some time, a new binary named `main` will appear at the root of the project. Try to start the binary like this:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\n./heroes-service\n```\n\n![Screenshot app started but no network](docs/images/start-app-no-network.png)\n\nAt this point, it won't work because there is no network deployed that the SDK can talk with. We will first start the network and then launch the app again:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service/fixtures \u0026\u0026 \\\ndocker-compose up -d \u0026\u0026 \\\ncd .. \u0026\u0026 \\\n./heroes-service\n```\n\n![Screenshot app started and SDK initialised](docs/images/start-app-initialized.png)\n\n\u003e **Note**: you need to see \"Initialization Successful\". If it's not the case then something went wrong.\n\nAlright! So we just initialised the SDK with our local network. In the next step, we will interact with a chaincode.\n\n### d. Clean up and Makefile\n\nThe Fabric SDK generates some files, like certificates, binaries and temporally files. Shutting down the network won't fully clean up your environment and when you will need to start it again, these files will be reused to avoid building process. For development you can keep them to test quickly but for a real test, you need to clean up all and start from the beginning.\n\n*How to clean up my environment ?*\n\n- Shut down your network: `cd $GOPATH/src/github.com/chainHero/heroes-service/fixtures \u0026\u0026 docker-compose down`\n- Remove credential stores (defined in the [config](config.yaml) file, in `client.credentialStore` section): `rm -rf /tmp/heroes-service-*`\n- Remove some docker containers and docker images not generated by the `docker-compose` command:\n\n```bash\ndocker rm -f -v `docker ps -a --no-trunc | grep \"heroes-service\" | cut -d ' ' -f 1` 2\u003e/dev/null\n```\n\nand\n\n```bash\ndocker rmi `docker images --no-trunc | grep \"heroes-service\" | cut -d ' ' -f 1` 2\u003e/dev/null\n```\n\n*How to be more efficient ?*\n\nWe can automatize all these tasks in one single step. Also the build and start process can be automated. To do so, we will create a Makefile. First, ensure that you have the tool:\n\n```bash\nmake --version\n```\n\nIf `make` is not installed do (Ubuntu):\n\n```bash\nsudo apt install make\n```\n\nThen create a file named `Makefile` at the root of the project with this content:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi Makefile\n```\n\n```makefile\n.PHONY: all dev clean build env-up env-down run\n\nall: clean build env-up run\n\ndev: build run\n\n##### BUILD\nbuild:\n\t@echo \"Build ...\"\n\t@dep ensure\n\t@go build\n\t@echo \"Build done\"\n\n##### ENV\nenv-up:\n\t@echo \"Start environment ...\"\n\t@cd fixtures \u0026\u0026 docker-compose up --force-recreate -d\n\t@echo \"Environment up\"\n\nenv-down:\n\t@echo \"Stop environment ...\"\n\t@cd fixtures \u0026\u0026 docker-compose down\n\t@echo \"Environment down\"\n\n##### RUN\nrun:\n\t@echo \"Start app ...\"\n\t@./heroes-service\n\n##### CLEAN\nclean: env-down\n\t@echo \"Clean up ...\"\n\t@rm -rf /tmp/heroes-service-* heroes-service\n\t@docker rm -f -v `docker ps -a --no-trunc | grep \"heroes-service\" | cut -d ' ' -f 1` 2\u003e/dev/null || true\n\t@docker rmi `docker images --no-trunc | grep \"heroes-service\" | cut -d ' ' -f 1` 2\u003e/dev/null || true\n\t@echo \"Clean up done\"\n```\n\nThe file is available here: [`Makefile`](Makefile)\n\nNow with the task `all`:\n1. the whole environment will be cleaned up,\n2. then our go program will be compiled,\n3. after which the network will be deployed and\n4. finally the app will be up and running.\n\nTo use it, go in the root of the project and use the `make` command:\n\n- Task `all`: `make` or `make all`\n- Task `clean`: clean up everything and put down the network (`make clean`)\n- Task `build`: just build the application (`make build`)\n- Task `env-up`: just make the network up (`make env-up`)\n- ...\n\n### e. Install \u0026 instantiate the chaincode\n\nWe are almost there to use the blockchain system. But for now we haven't set up any chaincode (smart contract) yet that will handle queries from our application. First, let's create a new directory named `chaincode` and add a new file named `main.go` (this is the main entry point of our smart-contract):\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nmkdir chaincode \u0026\u0026 \\\nvi chaincode/main.go\n```\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/hyperledger/fabric/core/chaincode/shim\"\n\tpb \"github.com/hyperledger/fabric/protos/peer\"\n)\n\n// HeroesServiceChaincode implementation of Chaincode\ntype HeroesServiceChaincode struct {\n}\n\n// Init of the chaincode\n// This function is called only one when the chaincode is instantiated.\n// So the goal is to prepare the ledger to handle future requests.\nfunc (t *HeroesServiceChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {\n\tfmt.Println(\"########### HeroesServiceChaincode Init ###########\")\n\n\t// Get the function and arguments from the request\n\tfunction, _ := stub.GetFunctionAndParameters()\n\n\t// Check if the request is the init function\n\tif function != \"init\" {\n\t\treturn shim.Error(\"Unknown function call\")\n\t}\n\n\t// Put in the ledger the key/value hello/world\n\terr := stub.PutState(\"hello\", []byte(\"world\"))\n\tif err != nil {\n\t\treturn shim.Error(err.Error())\n\t}\n\n\t// Return a successful message\n\treturn shim.Success(nil)\n}\n\n// Invoke\n// All future requests named invoke will arrive here.\nfunc (t *HeroesServiceChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {\n\tfmt.Println(\"########### HeroesServiceChaincode Invoke ###########\")\n\n\t// Get the function and arguments from the request\n\tfunction, args := stub.GetFunctionAndParameters()\n\n\t// Check whether it is an invoke request\n\tif function != \"invoke\" {\n\t\treturn shim.Error(\"Unknown function call\")\n\t}\n\n\t// Check whether the number of arguments is sufficient\n\tif len(args) \u003c 1 {\n\t\treturn shim.Error(\"The number of arguments is insufficient.\")\n\t}\n\t\n\t// In order to manage multiple type of request, we will check the first argument.\n\t// Here we have one possible argument: query (every query request will read in the ledger without modification)\n\tif args[0] == \"query\" {\n\t\treturn t.query(stub, args)\n\t}\n\n\treturn shim.Error(\"Unknown action, check the first argument\")\n}\n\n// query\n// Every readonly functions in the ledger will be here\nfunc (t *HeroesServiceChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {\n\tfmt.Println(\"########### HeroesServiceChaincode query ###########\")\n\n\t// Check whether the number of arguments is sufficient\n\tif len(args) \u003c 2 {\n\t\treturn shim.Error(\"The number of arguments is insufficient.\")\n\t}\n\n\t// Like the Invoke function, we manage multiple type of query requests with the second argument.\n\t// We also have only one possible argument: hello\n\tif args[1] == \"hello\" {\n\n\t\t// Get the state of the value matching the key hello in the ledger\n\t\tstate, err := stub.GetState(\"hello\")\n\t\tif err != nil {\n\t\t\treturn shim.Error(\"Failed to get state of hello\")\n\t\t}\n\n\t\t// Return this value in response\n\t\treturn shim.Success(state)\n\t}\n\n\t// If the arguments given don’t match any function, we return an error\n\treturn shim.Error(\"Unknown query action, check the second argument.\")\n}\n\nfunc main() {\n\t// Start the chaincode and make it ready for futures requests\n\terr := shim.Start(new(HeroesServiceChaincode))\n\tif err != nil {\n\t\tfmt.Printf(\"Error starting Heroes Service chaincode: %s\", err)\n\t}\n}\n```\n\nThe file is available here: [`chaincode/main.go`](chaincode/main.go)\n\n\u003e **Note**: the chaincode isn't really related to the application, we can have one repository for the app and another for the chaincode. For your information, today the chaincode can also be written in other languages like Java.\n\nFor now, the chaincode does nothing extraordinary, just put the key/value `hello`/`world` in the ledger at initialization. In addition, there is one function that we can call by an invoke: `query hello`. This function gets the state of the ledger, i.e. `hello` and give it in response. We will test this in the next step, after successfully install and instantiate the chaincode.\n\nIn order to install and instantiate the chaincode, we need to add some code in the application. Edit the [`blockchain/setup.go`](blockchain/setup.go) with those following lines:\n\n```go\npackage blockchain\n\nimport (\n\t\"fmt\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/client/channel\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/client/event\"\n\tmspclient \"github.com/hyperledger/fabric-sdk-go/pkg/client/msp\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/core/config\"\n\tpackager \"github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk\"\n\t\"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/cauthdsl\"\n\t\"github.com/pkg/errors\"\n)\n\n// FabricSetup implementation\ntype FabricSetup struct {\n\tConfigFile      string\n\tOrgID           string\n\tOrdererID\tstring\n\tChannelID       string\n\tChainCodeID     string\n\tinitialized     bool\n\tChannelConfig   string\n\tChaincodeGoPath string\n\tChaincodePath   string\n\tOrgAdmin        string\n\tOrgName         string\n\tUserName        string\n\tclient          *channel.Client\n\tadmin           *resmgmt.Client\n\tsdk             *fabsdk.FabricSDK\n\tevent           *event.Client\n}\n[...]\n\nfunc (setup *FabricSetup) InstallAndInstantiateCC() error {\n\n\t// Create the chaincode package that will be sent to the peers\n\tccPkg, err := packager.NewCCPackage(setup.ChaincodePath, setup.ChaincodeGoPath)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create chaincode package\")\n\t}\n\tfmt.Println(\"ccPkg created\")\n\n\t// Install example cc to org peers\n\tinstallCCReq := resmgmt.InstallCCRequest{Name: setup.ChainCodeID, Path: setup.ChaincodePath, Version: \"0\", Package: ccPkg}\n\t_, err = setup.admin.InstallCC(installCCReq, resmgmt.WithRetry(retry.DefaultResMgmtOpts))\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to install chaincode\")\n\t}\n\tfmt.Println(\"Chaincode installed\")\n\n\t// Set up chaincode policy\n\tccPolicy := cauthdsl.SignedByAnyMember([]string{\"org1.hf.chainhero.io\"})\n\n\tresp, err := setup.admin.InstantiateCC(setup.ChannelID, resmgmt.InstantiateCCRequest{Name: setup.ChainCodeID, Path: setup.ChaincodeGoPath, Version: \"0\", Args: [][]byte{[]byte(\"init\")}, Policy: ccPolicy})\n\tif err != nil || resp.TransactionID == \"\" {\n\t\treturn errors.WithMessage(err, \"failed to instantiate the chaincode\")\n\t}\n\tfmt.Println(\"Chaincode instantiated\")\n\n\t// Channel client is used to query and execute transactions\n\tclientContext := setup.sdk.ChannelContext(setup.ChannelID, fabsdk.WithUser(setup.UserName))\n\tsetup.client, err = channel.New(clientContext)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create new channel client\")\n\t}\n\tfmt.Println(\"Channel client created\")\n\n\t// Creation of the client which will enables access to our channel events\n\tsetup.event, err = event.New(clientContext)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create new event client\")\n\t}\n\tfmt.Println(\"Event client created\")\n\n\tfmt.Println(\"Chaincode Installation \u0026 Instantiation Successful\")\n\treturn nil\n}\n[...]\n```\n\nThe file is available here: [`blockchain/setup.go`](blockchain/setup.go)\n\n\u003e **Tips**: take care of the chaincode version, if you want to update your chaincode, increment the version number set at the line 105 of this [`setup.go`](blockchain/setup.go) file. Otherwise the network will keep the same chaincode.\n\nWe need now to modify our `main.go` file in order to call our new function\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi main.go\n```\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/chainHero/heroes-service/blockchain\"\n\t\"os\"\n)\n\nfunc main() {\n\t// Definition of the Fabric SDK properties\n\tfSetup := blockchain.FabricSetup{\n\t\t// Network parameters\n      \tOrdererID: \"orderer.hf.chainhero.io\",\n      \t\n\t\t// Channel parameters\n\t\tChannelID:     \"chainhero\",\n\t\tChannelConfig: os.Getenv(\"GOPATH\") + \"/src/github.com/chainHero/heroes-service/fixtures/artifacts/chainhero.channel.tx\",\n\n\t\t// Chaincode parameters\n\t\tChainCodeID:     \"heroes-service\",\n\t\tChaincodeGoPath: os.Getenv(\"GOPATH\"),\n\t\tChaincodePath:   \"github.com/chainHero/heroes-service/chaincode/\",\n\t\tOrgAdmin:        setup.OrgAdmin,\n\t\tOrgName:         \"org1\",\n\t\tConfigFile:      \"config.yaml\",\n\n\t\t// User parameters\n\t\tUserName: \"User1\",\n\t}\n[...]\n\t// Install and instantiate the chaincode\n\terr = fSetup.InstallAndInstantiateCC()\n\tif err != nil {\n\t\tfmt.Printf(\"Unable to install and instantiate the chaincode: %v\\n\", err)\n\t\treturn\n\t}\n}\n\n```\n\nThe file is available here: [`main.go`](main.go)\n\nWe can test this, just with the `make` command setup in the previous step:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nmake\n```\n\n![Screenshot Chaincode installed and instantiated](docs/images/install-and-instantiate-cc.png)\n\n\u003e **Tips**: the installation and the instantiation don't need to be run at every start of the application. Only when we update the chaincode (and the chaincode version). A solution is to provide an argument when we run the application to tell to do this additional procedure before move on. Since in this tutorial we will clean up the environment every time we don't really care about that.\n\n### f. Query the chaincode\n\nLike a database, the chaincode is plugged and ready to answer. Let's try the `hello` query.\n\nWe will put all query functions in a new file named `query.go` in the `blockchain` folder:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi blockchain/query.go\n```\n\n```go\npackage blockchain\n\nimport (\n\t\"fmt\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/client/channel\"\n)\n\n// QueryHello query the chaincode to get the state of hello\nfunc (setup *FabricSetup) QueryHello() (string, error) {\n\n\t// Prepare arguments\n\tvar args []string\n\targs = append(args, \"invoke\")\n\targs = append(args, \"query\")\n\targs = append(args, \"hello\")\n\n\tresponse, err := setup.client.Query(channel.Request{ChaincodeID: setup.ChainCodeID, Fcn: args[0], Args: [][]byte{[]byte(args[1]), []byte(args[2])}})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to query: %v\", err)\n\t}\n\n\treturn string(response.Payload), nil\n}\n```\n\nThe file is available here: [`blockchain/query.go`](blockchain/query.go)\n\nYou can add the call to this new function in the [`main.go`](main.go):\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi main.go\n```\n\n```go\nfunc main() {\n\n[...]\n\n\t// Query the chaincode\n\tresponse, err := fSetup.QueryHello()\n\tif err != nil {\n\t\tfmt.Printf(\"Unable to query hello on the chaincode: %v\\n\", err)\n\t} else {\n\t\tfmt.Printf(\"Response from the query hello: %s\\n\", response)\n\t}\n}\n```\n\nLet's try:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nmake\n```\n\n![Screenshot Query Hello](docs/images/query-hello.png)\n\n### g. Change the ledger state\n\nThe next thing to do in order to make a basic tour of the Fabric SDK Go, is to make a request to the chaincode in order to change the ledger state.\n\nFirst, we will add this ability in the chaincode. Edit the [`chaincode/main.go`](chaincode/main.go) file:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi chaincode/main.go\n```\n\n```go\n[...]\n\n// Invoke\n// All future requests named invoke will arrive here.\nfunc (t *HeroesServiceChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {\n\tfmt.Println(\"########### HeroesServiceChaincode Invoke ###########\")\n\n\t// Get the function and arguments from the request\n\tfunction, args := stub.GetFunctionAndParameters()\n\n\t// Check whether it is an invoke request\n\tif function != \"invoke\" {\n\t\treturn shim.Error(\"Unknown function call\")\n\t}\n\n\t// Check whether the number of arguments is sufficient\n\tif len(args) \u003c 1 {\n\t\treturn shim.Error(\"The number of arguments is insufficient.\")\n\t}\n\n\t// In order to manage multiple type of request, we will check the first argument.\n\t// Here we have one possible argument: query (every query request will read in the ledger without modification)\n\tif args[0] == \"query\" {\n\t\treturn t.query(stub, args)\n\t}\n\n\t// The update argument will manage all update in the ledger\n\tif args[0] == \"invoke\" {\n\t\treturn t.invoke(stub, args)\n\t}\n\n\t// If the arguments given don’t match any function, we return an error\n\treturn shim.Error(\"Unknown action, check the first argument\")\n}\n\n[...]\n\n// invoke\n// Every functions that read and write in the ledger will be here\nfunc (t *HeroesServiceChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {\n\tfmt.Println(\"########### HeroesServiceChaincode invoke ###########\")\n\n\tif len(args) \u003c 2 {\n\t\treturn shim.Error(\"The number of arguments is insufficient.\")\n\t}\n\n\t// Check if the ledger key is \"hello\" and process if it is the case. Otherwise it returns an error.\n\tif args[1] == \"hello\" \u0026\u0026 len(args) == 3 {\n\n\t\t// Write the new value in the ledger\n\t\terr := stub.PutState(\"hello\", []byte(args[2]))\n\t\tif err != nil {\n\t\t\treturn shim.Error(\"Failed to update state of hello\")\n\t\t}\n\n\t\t// Notify listeners that an event \"eventInvoke\" have been executed (check line 19 in the file invoke.go)\n\t\terr = stub.SetEvent(\"eventInvoke\", []byte{})\n\t\tif err != nil {\n\t\t\treturn shim.Error(err.Error())\n\t\t}\n\n\t\t// Return this value in response\n\t\treturn shim.Success(nil)\n\t}\n\n\t// If the arguments given don’t match any function, we return an error\n\treturn shim.Error(\"Unknown invoke action, check the second argument.\")\n}\n\n[...]\n```\n\nThe file is available here: [`chaincode/main.go`](chaincode/main.go)\n\nFrom the application side, we add a new function to make the invocation of the chaincode. Add a file named `invoke.go` in the `blockchain` folder:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi blockchain/invoke.go\n```\n\n```go\npackage blockchain\n\nimport (\n\t\"fmt\"\n\t\"github.com/hyperledger/fabric-sdk-go/pkg/client/channel\"\n\t\"time\"\n)\n\n// InvokeHello\nfunc (setup *FabricSetup) InvokeHello(value string) (string, error) {\n\n\t// Prepare arguments\n\tvar args []string\n\targs = append(args, \"invoke\")\n\targs = append(args, \"invoke\")\n\targs = append(args, \"hello\")\n\targs = append(args, value)\n\n\teventID := \"eventInvoke\"\n\n\t// Add data that will be visible in the proposal, like a description of the invoke request\n\ttransientDataMap := make(map[string][]byte)\n\ttransientDataMap[\"result\"] = []byte(\"Transient data in hello invoke\")\n\n\treg, notifier, err := setup.event.RegisterChaincodeEvent(setup.ChainCodeID, eventID)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer setup.event.Unregister(reg)\n\n\t// Create a request (proposal) and send it\n\tresponse, err := setup.client.Execute(channel.Request{ChaincodeID: setup.ChainCodeID, Fcn: args[0], Args: [][]byte{[]byte(args[1]), []byte(args[2]), []byte(args[3])}, TransientMap: transientDataMap})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to move funds: %v\", err)\n\t}\n\n\t// Wait for the result of the submission\n\tselect {\n\tcase ccEvent := \u003c-notifier:\n\t\tfmt.Printf(\"Received CC event: %s\\n\", ccEvent)\n\tcase \u003c-time.After(time.Second * 20):\n\t\treturn \"\", fmt.Errorf(\"did NOT receive CC event for eventId(%s)\", eventID)\n\t}\n\n\treturn string(response.TransactionID), nil\n}\n\n```\n\nThe file is available here: [`blockchain/invoke.go`](blockchain/invoke.go)\n\nYou can then add the call to this function in the [`main.go`](main.go):\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nvi main.go\n```\n\n```go\nfunc main() {\n\n[...]\n\n\t// Query the chaincode\n\tresponse, err := fSetup.QueryHello()\n\tif err != nil {\n\t\tfmt.Printf(\"Unable to query hello on the chaincode: %v\\n\", err)\n\t} else {\n\t\tfmt.Printf(\"Response from the query hello: %s\\n\", response)\n\t}\n\n\t// Invoke the chaincode\n\ttxId, err := fSetup.InvokeHello(\"chainHero\")\n\tif err != nil {\n\t\tfmt.Printf(\"Unable to invoke hello on the chaincode: %v\\n\", err)\n\t} else {\n\t\tfmt.Printf(\"Successfully invoke hello, transaction ID: %s\\n\", txId)\n\t}\n\n\t// Query again the chaincode\n\tresponse, err = fSetup.QueryHello()\n\tif err != nil {\n\t\tfmt.Printf(\"Unable to query hello on the chaincode: %v\\n\", err)\n\t} else {\n\t\tfmt.Printf(\"Response from the query hello: %s\\n\", response)\n\t}\n}\n```\n\nLet's try:\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service \u0026\u0026 \\\nmake\n```\n\n![Screenshot Invoke Hello](docs/images/invoke-hello.png)\n\n\u003e **Note**: this error message may appear: `endorsement validation failed: Endorser Client Status Code: (3) ENDORSEMENT_MISMATCH. Description: ProposalResponsePayloads do not match`. Since we have two PEERs, the SDK sends its request to the two directly and if it receives a different answer (which is quite possible because it's an asynchronous system) then it returns this error. The best thing to do in these cases is to start over again.\n\n## 6. Make this in a web application\n\nWe also can make this usable for any user. The best choice is a web application and we are lucky because the Go language natively provides a web server handling HTTP requests and also templating for HTML.\n\nFor now, we have only two different actions: the query and the invocation of the hello value. Let's make two HTML pages for each action. We add a [`web`](web) directory with three other directories:\n- [`web/templates`](web/templates): contains all HTML pages (templates)\n- [`web/assets`](web/assets): contains all CSS, Javascript, Fonts, Images...\n- [`web/controllers`](web/controllers): contains all functions that will render templates\n\nWe use the MVC (Model-View-Controller) to make it more readable. The Model will be the blockchain part, the View are templates and Controller are provided by functions in the [`controllers`](web/controllers) directory.\n\nPopulate each with the appropriate code (we also added Bootstrap to make the result a little prettier:\n\n- [`web/templates/layout.html`](web/templates/layout.html)\n- [`web/templates/home.html`](web/templates/home.html)\n- [`web/templates/request.html`](web/templates/request.html)\n- [`web/controllers/controller.go`](web/controllers/controller.go)\n- [`web/controllers/home.go`](web/controllers/home.go)\n- [`web/controllers/request.go`](web/controllers/request.go)\n- [`web/app.go`](web/app.go)\n- [`web/assets`](web/assets)\n\nAnd finally, we change the [`main.go`](main.go), in order to use the web interface instead of directly query the blockchain.\n\n- [`main.go`](main.go)\n\nRun the app and go to [localhost:3000/home.html](http://localhost:3000/home.html):\n\n```bash\ncd $GOPATH/src/github.com/chainHero/heroes-service ; \\\nmake\n```\n\nThe `home` page make a query in the blockchain to get the value of the `hello` key and display it.\n\n![Screenshot Web Home Hello World](docs/images/web-home-hello-world.png)\n\nThe `request` page has a form to change the `hello` value. \n\n![Screenshot Web Request Write](docs/images/web-request-write.png)\n\nAfter a successful submission the transaction ID is given.\n\n![Screenshot Web Request Success](docs/images/web-request-success.png)\n\nWe can see the change by going back to the `home` page.\n\n![Screenshot Web Home Hello Superman](docs/images/web-home-hello-superman.png)\n\n**It's the end for the first part. A more complex application is coming.**\n\n## 7. References\n\n- [Hyperledger website](https://www.hyperledger.org/)\n- [Hyperledger Fabric online documentation](http://hyperledger-fabric.readthedocs.io/en/latest/)\n- [Hyperledger Fabric on github](https://github.com/hyperledger/fabric)\n- [Hyperledger Fabric Certificate Authority on github](https://github.com/hyperledger/fabric-ca)\n- [Hyperledger Fabric SDK Go on github](https://github.com/hyperledger/fabric-sdk-go)\n- [Fabric SDK Go tests](https://github.com/hyperledger/fabric-sdk-go/blob/master/test/integration/end_to_end_test.go)\n- [CLI](https://github.com/securekey/fabric-examples/tree/master/fabric-cli/): An example CLI for Fabric built with the Go SDK.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchainhero%2Fheroes-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchainhero%2Fheroes-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchainhero%2Fheroes-service/lists"}