<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pau Aragonès Sabaté</title>
    <description>The latest articles on DEV Community by Pau Aragonès Sabaté (@vanitas92).</description>
    <link>https://dev.to/vanitas92</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F433316%2Fcc2c3725-0c1c-4c03-991e-7b07497a0f36.jpeg</url>
      <title>DEV Community: Pau Aragonès Sabaté</title>
      <link>https://dev.to/vanitas92</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vanitas92"/>
    <language>en</language>
    <item>
      <title>How to implement Hyperledger Fabric External Chaincodes within a Kubernetes cluster</title>
      <dc:creator>Pau Aragonès Sabaté</dc:creator>
      <pubDate>Tue, 21 Jul 2020 14:54:31 +0000</pubDate>
      <link>https://dev.to/vanitas92/how-to-implement-hyperledger-fabric-external-chaincodes-within-a-kubernetes-cluster-34de</link>
      <guid>https://dev.to/vanitas92/how-to-implement-hyperledger-fabric-external-chaincodes-within-a-kubernetes-cluster-34de</guid>
      <description>&lt;p&gt;Recently released Hyperledger Fabric 2.0 was very welcomed as it introduced some interesting features on how to manage the chaincode with its new decentralized governance for chaincodes, private data enhancements and the ability to use the External chaincode launcher.&lt;/p&gt;

&lt;p&gt;The last feature mentioned finally eliminates the docker dependency for launching chaincodes, which caused many difficulties in setting the blockchain networks in some environments, specially when not using the &lt;strong&gt;docker-compose&lt;/strong&gt; setting that is used as tutorials on the &lt;a href="https://hyperledger-fabric.readthedocs.io/en/release-2.0/test_network.html"&gt;Hyperledger Fabric official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since the distribution of the blockchain components are done through Docker, many use cases have been developed using Kubernetes as the container orchestration platform to launch the entire or some part of the blockchain network, and the dependency of the Docker daemon in the peer leaded to some configurations that might not be acceptable in production environments, such as the use of the Docker Socket of the worker nodes in the peer to deploy the chaincode containers, hence making these containers out of Kubernetes domain, or the use of &lt;strong&gt;Docker-in-Docker (DinD)&lt;/strong&gt; solutions, which required these containers to be privileged.&lt;/p&gt;

&lt;p&gt;With these constraints and limitations, the newly released version enables the preferred way on how these chaincodes are deployed, and in this tutorial, jointly made with Laura Esbri, we are going to see how to deploy them using the &lt;strong&gt;External Chaincodes launcher&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;The following is a list of what we are going to need in order to make a simple Fabric network work within a dev Kubernetes cluster.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Kubernetes cluster&lt;/strong&gt;. It can perfectly be one cluster using simple tools such as &lt;code&gt;minikube&lt;/code&gt; or a single-node &lt;code&gt;kubeadm&lt;/code&gt; cluster. The latter is the environment we are going to showcase here. You will need the tools to manage a Kubernetes cluster such as &lt;code&gt;kubectl&lt;/code&gt;. Setting up a K8s cluster is out of scope in this article.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hyperledger Fabric 2.2.0 docker images&lt;/strong&gt;. The images will be pulled when we are launching the deployments of the Kubernetes yaml descriptors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hyperledger Fabric 2.2.0 binaries&lt;/strong&gt;. We will need them to create the &lt;code&gt;crypto-config&lt;/code&gt; and the &lt;code&gt;channel-artifacts&lt;/code&gt;. You can download them in this &lt;a href="https://github.com/hyperledger/fabric/releases/download/v2.2.0/hyperledger-fabric-linux-amd64-2.2.0.tar.gz"&gt;link&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will find the repository with all the files used in this tutorial here: &lt;a href="https://github.com/vanitas92/fabric-external-chaincodes"&gt;https://github.com/vanitas92/fabric-external-chaincodes&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Install the binaries
&lt;/h1&gt;

&lt;p&gt;Install the binaries required using the following instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget https://github.com/hyperledger/fabric/releases/download/v2.1.0/hyperledger-fabric-linux-amd64-2.2.0.tar.gz

tar -xzf hyperledger-fabric-linux-amd64-2.2.0.tar.gz

# Move to the bin path
mv bin/* /bin

# Check that you have successfully installed the tools by executing

configtxgen --version

# Should print the following output:
# configtxgen:
#  Version: 2.2.0
#  Commit SHA: 5ea85bc54
#  Go version: go1.14.4
#  OS/Arch: linux/amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Launching the network
&lt;/h1&gt;

&lt;p&gt;Once we have the Kubernetes cluster up and ready, we will launch the network. But first we need to generate the basic crypto material necessary to establish the identity and the genesis block of the network. There has been some changes in the &lt;code&gt;configtx.yaml&lt;/code&gt; file that are needed to be implemented in order to make the new chaincode lifecycle work, which are necessary to use the External Chaincode Launcher.&lt;/p&gt;

&lt;p&gt;The blockchain network will consist of a RAFT orderer service with 3 instances, 2 organisations that have a peer for each one (&lt;em&gt;org1&lt;/em&gt; and &lt;em&gt;org2&lt;/em&gt;) with a CA for each organisation. This is already encoded in the &lt;code&gt;configtx.yaml&lt;/code&gt; and &lt;code&gt;crypto-config.yaml&lt;/code&gt; and there is no need to modify these files.&lt;/p&gt;

&lt;p&gt;There are a few new configuration options on &lt;code&gt;configtx.yaml&lt;/code&gt; as the new lifecycle and endorsement policies. These options can be defined in this file to set which role is allowed to sign when an endorsement action is happening in the network. In this case, we have set this to the peers that belong to the organization MSP, with the &lt;code&gt;Endorsement&lt;/code&gt; policy option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Organizations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;org1&lt;/span&gt;
        &lt;span class="c1"&gt;# DefaultOrg defines the organization which is used in the sampleconfig&lt;/span&gt;
        &lt;span class="c1"&gt;# of the fabric.git development environment&lt;/span&gt;
        &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org1MSP&lt;/span&gt;

        &lt;span class="c1"&gt;# ID to load the MSP definition as&lt;/span&gt;
        &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org1MSP&lt;/span&gt;

        &lt;span class="na"&gt;MSPDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crypto-config/peerOrganizations/org1/msp&lt;/span&gt;

        &lt;span class="c1"&gt;# Policies defines the set of policies at this level of the config tree&lt;/span&gt;
        &lt;span class="c1"&gt;# For organization policies, their canonical path is usually&lt;/span&gt;
        &lt;span class="c1"&gt;#   /Channel/&amp;lt;Application|Orderer&amp;gt;/&amp;lt;OrgName&amp;gt;/&amp;lt;PolicyName&amp;gt;&lt;/span&gt;
        &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;org1Policies&lt;/span&gt;
            &lt;span class="na"&gt;Readers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org1MSP.admin',&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'org1MSP.peer',&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'org1MSP.client')"&lt;/span&gt;
            &lt;span class="na"&gt;Writers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org1MSP.admin',&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'org1MSP.client')"&lt;/span&gt;
            &lt;span class="na"&gt;Admins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org1MSP.admin')"&lt;/span&gt;
            &lt;span class="na"&gt;Endorsement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org1MSP.peer')"&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;org2&lt;/span&gt;
        &lt;span class="c1"&gt;# DefaultOrg defines the organization which is used in the sampleconfig&lt;/span&gt;
        &lt;span class="c1"&gt;# of the fabric.git development environment&lt;/span&gt;
        &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org2MSP&lt;/span&gt;

        &lt;span class="c1"&gt;# ID to load the MSP definition as&lt;/span&gt;
        &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org2MSP&lt;/span&gt;

        &lt;span class="na"&gt;MSPDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crypto-config/peerOrganizations/org2/msp&lt;/span&gt;

        &lt;span class="c1"&gt;# Policies defines the set of policies at this level of the config tree&lt;/span&gt;
        &lt;span class="c1"&gt;# For organization policies, their canonical path is usually&lt;/span&gt;
        &lt;span class="c1"&gt;#   /Channel/&amp;lt;Application|Orderer&amp;gt;/&amp;lt;OrgName&amp;gt;/&amp;lt;PolicyName&amp;gt;&lt;/span&gt;
        &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;org2Policies&lt;/span&gt;
            &lt;span class="na"&gt;Readers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org2MSP.admin',&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'org2MSP.peer',&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'org2MSP.client')"&lt;/span&gt;
            &lt;span class="na"&gt;Writers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org2MSP.admin',&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'org2MSP.client')"&lt;/span&gt;
            &lt;span class="na"&gt;Admins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org2MSP.admin')"&lt;/span&gt;
            &lt;span class="na"&gt;Endorsement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Signature&lt;/span&gt;
                &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OR('org2MSP.peer')"&lt;/span&gt;

        &lt;span class="na"&gt;AnchorPeers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# AnchorPeers defines the location of peers which can be used&lt;/span&gt;
            &lt;span class="c1"&gt;# for cross org gossip communication.  Note, this value is only&lt;/span&gt;
            &lt;span class="c1"&gt;# encoded in the genesis block in the Application section context&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;peer0-org2&lt;/span&gt;
              &lt;span class="na"&gt;Port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7051&lt;/span&gt;
            &lt;span class="c1"&gt;# - Host: peer1-org2&lt;/span&gt;
            &lt;span class="c1"&gt;#   Port: 7051&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we can set the application capabilities to set the signing policies when there is an endorsement happening. There are two rules to be defined, the &lt;code&gt;LifecycleEndorsement&lt;/code&gt; and the &lt;code&gt;Endorsement&lt;/code&gt; rules. We set them to the &lt;code&gt;MAJORITY&lt;/code&gt; rule, which indicates that any endorsement must be approved by more than half of the network participants (50% + 1 signatures required):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Application&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;ApplicationDefaults&lt;/span&gt;
    &lt;span class="c1"&gt;# Organizations is the list of orgs which are defined as participants on&lt;/span&gt;
    &lt;span class="c1"&gt;# the application side of the network&lt;/span&gt;
    &lt;span class="na"&gt;Organizations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;# Policies defines the set of policies at this level of the config tree&lt;/span&gt;
    &lt;span class="c1"&gt;# For Application policies, their canonical path is&lt;/span&gt;
    &lt;span class="c1"&gt;#   /Channel/Application/&amp;lt;PolicyName&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;ApplicationDefaultPolicies&lt;/span&gt;
        &lt;span class="na"&gt;Readers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ImplicitMeta&lt;/span&gt;
            &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ANY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Readers"&lt;/span&gt;
        &lt;span class="na"&gt;Writers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ImplicitMeta&lt;/span&gt;
            &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ANY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Writers"&lt;/span&gt;
        &lt;span class="na"&gt;Admins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ImplicitMeta&lt;/span&gt;
            &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MAJORITY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Admins"&lt;/span&gt;
        &lt;span class="na"&gt;LifecycleEndorsement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ImplicitMeta&lt;/span&gt;
            &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MAJORITY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Endorsement"&lt;/span&gt;
        &lt;span class="na"&gt;Endorsement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ImplicitMeta&lt;/span&gt;
            &lt;span class="na"&gt;Rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MAJORITY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Endorsement"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you are all set with the configuration of the network, you can now generate the crypto materials and the genesis block of the blockchain network. We will use the &lt;code&gt;fabricOps.sh&lt;/code&gt; script with the following command:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Make sure that this script has execution permissions. Changing to 744 permision should be enough.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./fabricOps.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create all the crypto materials such as all the certificates of the peers orderers and CAs, as well as the genesis block of the channel.&lt;/p&gt;

&lt;p&gt;We will first need to create a new namespace for the Hyperledger Fabric workload, create one with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create ns hyperledger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a folder in the VM for storing the persistent data for all the Hyperledger Fabric workload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /home/storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have created the namespace, we are ready to deploy the workload:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Check and modify if needed the hostpath of the volumes attached on the orderers’ deployment, the yamls use absolute paths and it is assumed here that the repository is in the &lt;code&gt;/home&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; orderer-service/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that everything is running fine by issuing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; hyperledger

&lt;span class="c"&gt;### Should print a similar output&lt;/span&gt;
NAME                        READY   STATUS    RESTARTS   AGE
orderer0-58666b6bd7-pflf7   1/1     Running   0          5m47s
orderer1-c4fd65c7d-c27ll    1/1     Running   0          5m47s
orderer2-557cb7865-wlcmh    1/1     Running   0          5m47s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note 2&lt;/strong&gt;: Again, check and modify if needed the hostpath of the volumes attached on the peer, CA and CLI deployments, the yamls use absolute paths and it is assumed here that the repository is in the &lt;code&gt;/home&lt;/code&gt; folder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now create the &lt;strong&gt;org1&lt;/strong&gt; workload, which will deploy the peer and the CA of this organisation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl create -f org1/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that everything is running fine by issuing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                          READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-9px4s      1/1     Running   0          19m
cli-org1-bc9f895f6-zmmdc      1/1     Running   0        2m56s
orderer0-58666b6bd7-pflf7     1/1     Running   0          79m
orderer1-c4fd65c7d-c27ll      1/1     Running   0          79m
orderer2-557cb7865-wlcmh      1/1     Running   0          79m
peer0-org1-798b974467-vv4zz   1/1     Running   0          19m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repeat the same steps with &lt;strong&gt;org2&lt;/strong&gt; workload:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note 3&lt;/strong&gt;: Again, check and modify if needed the hostpath of the volumes attached on the peer, CA and CLI deployments, the yamls use absolute paths and it is assumed here that the repository is in the &lt;code&gt;/home&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl create -f org2/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that everything is running fine by issuing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                          READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-9px4s      1/1     Running   0          71m
ca-org2-7454f69c48-q8lft      1/1     Running   0        2m20s
cli-org1-bc9f895f6-zmmdc      1/1     Running   0          55m
cli-org2-7779cc8788-8q4ns     1/1     Running   0        2m20s
orderer0-58666b6bd7-pflf7     1/1     Running   0         131m
orderer1-c4fd65c7d-c27ll      1/1     Running   0         131m
orderer2-557cb7865-wlcmh      1/1     Running   0         131m
peer0-org1-798b974467-vv4zz   1/1     Running   0          71m
peer0-org2-5849c55fcd-mbn5h   1/1     Running   0        2m19s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All workload above should appear right now in the &lt;em&gt;hyperledger&lt;/em&gt; namespace.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note 4&lt;/strong&gt;: If there are CrashloopBackoff errors, check that the paths are correctly set and crypto files are in place and correctly set. Check the logs by issuing the &lt;code&gt;kubectl logs pod_name -n hyperledger&lt;/code&gt; command, pointing to the faulty pod.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Setting up the network channels
&lt;/h1&gt;

&lt;p&gt;Once all workload is deployed, we are ready to create the channel and join the peers to the channel. Enter in the cli pod of the &lt;strong&gt;org1&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl exec -it cli_org1_pod_name sh -n hyperledger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once inside the cli pod, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer channel create -o orderer0:7050 -c mychannel -f ./scripts/channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA

### Should print a similar output
2020-03-06 11:54:57.582 UTC [channelCmd] InitCmdFactory -&amp;gt; INFO 001 Endorser and orderer connections initialized
2020-03-06 11:54:58.903 UTC [cli.common] readBlock -&amp;gt; INFO 002 Received block: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The channel &lt;code&gt;mychannel&lt;/code&gt; is created and ready to be used. Next, join the peer of &lt;strong&gt;org1&lt;/strong&gt; to the channel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer channel join -b mychannel.block

### Should print a similar output
2020-03-06 12:01:41.608 UTC [channelCmd] InitCmdFactory -&amp;gt; INFO 001 Endorser and orderer connections initialized
2020-03-06 12:01:41.688 UTC [channelCmd] executeJoin -&amp;gt; INFO 002 Successfully submitted proposal to join channel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to perform the same steps on &lt;strong&gt;org2&lt;/strong&gt; cli, but since the channel is already created by &lt;strong&gt;org1&lt;/strong&gt;, we are going to fetch the genesis block from the orderer service. Enter the pod first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl exec -it cli_org2_pod_name sh -n hyperledger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once inside the cli pod, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer channel fetch 0 mychannel.block -c mychannel -o orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
2020-03-06 12:18:14.880 UTC [channelCmd] InitCmdFactory -&amp;gt; INFO 001 Endorser and orderer connections initialized
2020-03-06 12:18:14.895 UTC [cli.common] readBlock -&amp;gt; INFO 002 Received block: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then join to the channel from the genesis block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer channel join -b mychannel.block

### Should print a similar output
2020-03-06 12:20:41.475 UTC [channelCmd] InitCmdFactory -&amp;gt; INFO 001 Endorser and orderer connections initialized
2020-03-06 12:20:41.561 UTC [channelCmd] executeJoin -&amp;gt; INFO 002 Successfully submitted proposal to join channel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check anytime if any of the peers has joined the channel by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer channel list

### Should print a similar output
2020-03-06 12:22:41.102 UTC [channelCmd] InitCmdFactory -&amp;gt; INFO 001 Endorser and orderer connections initialized
Channels peers has joined: 
mychannel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing the External Chaincode
&lt;/h1&gt;

&lt;p&gt;Now we are going to do the interesting stuff 😄. We are going to deploy the marbles chaincode as an External chaincode. You can find the original chaincode in the &lt;a href="https://github.com/hyperledger/fabric-samples/tree/master/chaincode/marbles02/go"&gt;fabric-sample Github repository&lt;/a&gt;, but in order to deploy it as External Chaincode, we need to perform some changes in the imports and the init function to declare it as external chaincode server.&lt;/p&gt;

&lt;p&gt;The new version of Hyperledger also comes with the new chaincode lifecycle process for installing a chaincode on your peers and starting it on a channel. In order to use the &lt;a href="https://hyperledger-fabric.readthedocs.io/en/release-2.2/cc_launcher.html"&gt;External Chaincodes&lt;/a&gt; feature, we have to use this new process as well.&lt;/p&gt;

&lt;p&gt;The first thing we have to do is to configure the peer to process external chaincode. The external builders are merely based on buildpacks and so we have create 3 scripts, &lt;code&gt;detect&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;release&lt;/code&gt;. These 3 scripts have to be defined inside the peer container. These scripts can be found in the &lt;code&gt;buildpack/bin&lt;/code&gt; folder.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note 5&lt;/strong&gt;: Make sure that these 3 scripts have execution permissions in the &lt;code&gt;buildpack/bin&lt;/code&gt; folder. The scripts are executed in the peer pod as root so changing to 744 permission should be enough. Failing to do so will cause the externalbuilder to fail its execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The definition of the builders can be found inside the org1 folder in the &lt;code&gt;builders-config.yaml&lt;/code&gt;. This file has all the default options to configure the peer of the &lt;code&gt;core.yaml&lt;/code&gt; except the &lt;em&gt;core_chaincode_externalbuilders&lt;/em&gt; option, which has a custom builder configuration like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;            &lt;span class="c1"&gt;# List of directories to treat as external builders and launchers for&lt;/span&gt;
            &lt;span class="c1"&gt;# chaincode. The external builder detection processing will iterate over the&lt;/span&gt;
            &lt;span class="c1"&gt;# builders in the order specified below.&lt;/span&gt;
            &lt;span class="na"&gt;externalBuilders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;external-builder&lt;/span&gt;
                &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/builders/external&lt;/span&gt;
                &lt;span class="na"&gt;environmentWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GOPROXY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the Kubernetes deployment descriptors of the peers have environment variables to configure the option, these environment variables override the default option from the &lt;code&gt;core.yaml&lt;/code&gt;. This was done this way because the environment variables do not accept array formats and this way is able to configure each peer with his own configuration but establish this builder. It is used by all organizations in this network.&lt;/p&gt;

&lt;p&gt;The new lifecycle process packages the chaincode and installs it in a different way than previous versions. Since we are using the external chaincode feature, the chaincode code does not have to be compiled and installed within the peer pod itself, rather be on another pod. The only code to be installed in the peer process is the information required to be able to connect to the external chaincode process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note 6&lt;/strong&gt;: We are going to perform the steps for the &lt;strong&gt;org1&lt;/strong&gt; peer chaincode, hence execute the commands on the &lt;strong&gt;org1&lt;/strong&gt; cli pod. These steps will be repeated for &lt;strong&gt;org2&lt;/strong&gt; peer but changing some configuration of the chaincode later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To achieve this, we need to &lt;a href="https://hyperledger-fabric.readthedocs.io/en/release-2.2/cc_service.html#packaging-chaincode"&gt;package the chaincode&lt;/a&gt; with some requirements. There has to be a &lt;code&gt;connection.json&lt;/code&gt; file that contains the information of the connection to the external chaincode server. This includes the address, TLS certificates and dial timeout configurations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chaincode-marbles-org1.hyperledger:7052"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dial_timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tls_required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_auth_required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY-----"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_cert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"root_cert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file needs to be packaged into a tar file called &lt;code&gt;code.tar.gz&lt;/code&gt;. Achieve this by executing the following command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note 6&lt;/strong&gt;: You can perform these commands inside the cli tools pod or outside the cli pod in your host machine where your chaincode hostpath storage points. In the end, the resulting tar files are needed in the cli pod to launch commands, so i recommend it doing it from the cli pod. If you are going to perform these commands in the cli pod, then go to this path: &lt;code&gt;/opt/gopath/src/github.com/marbles/packaging&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd chaincode/packaging
$ tar cfz code.tar.gz connection.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the &lt;code&gt;code.tar.gz&lt;/code&gt; file, then we have to repackage it again alongside with another file called &lt;code&gt;metadata.json&lt;/code&gt;, which includes information about the type of chaincode to be processed, the path where the chaincode resides and the label we want to give to that chaincode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"external"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"marbles"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We package this two files with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tar cfz marbles-org1.tgz code.tar.gz metadata.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you got the tar file, you are ready to install it in the peer using the new lifecycle process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode install marbles-org1.tgz

### Should print a similar output
2020-03-07 14:33:18.120 UTC [cli.lifecycle.chaincode] submitInstallProposal -&amp;gt; INFO 001 Installed remotely: response:&amp;lt;status:200 payload:"\nGdmarbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064\022\006marbles" &amp;gt; 
2020-03-07 14:33:18.126 UTC [cli.lifecycle.chaincode] submitInstallProposal -&amp;gt; INFO 002 Chaincode code package identifier: marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the chaincode code package identifier as we will need it later. Nevertheless, you can always retrieve it back by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode queryinstalled

### Should print a similar output
Installed chaincodes on peer:
Package ID: marbles:030eec59c7d74fbb4e9fd57bbd50bb904a715ffb9de8fea85b6a6d4b8ca9ea12, Label: marbles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are going to repeat the same steps above for &lt;strong&gt;org2&lt;/strong&gt; but since we want to have a different pod to serve the same chaincode for &lt;strong&gt;org2&lt;/strong&gt; peer, we have to change the address config option in &lt;code&gt;connection.json&lt;/code&gt; file. Modify the file address value like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chaincode-marbles-org2.hyperledger:7052"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then repeat the same steps as before, executing the install command in the &lt;strong&gt;org2&lt;/strong&gt; cli pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rm -f code.tar.gz
$ tar cfz code.tar.gz connection.json
$ tar cfz marbles-org2.tgz code.tar.gz metadata.json
$ peer lifecycle chaincode install marbles-org2.tgz

### Should print a similar output
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -&amp;gt; INFO 001 Installed remotely: response:&amp;lt;status:200 payload:"\nGmarbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b\022\006marbles" &amp;gt; 
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -&amp;gt; INFO 002 Chaincode code package identifier: marbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the chaincode code package identifier as before. It should have a different hash from the &lt;strong&gt;org1&lt;/strong&gt; as we changed the address for &lt;strong&gt;org2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What happened in the peer while installing the chaincode? If there are some external builders or launchers defined in the peer, then they get executed before attempting the classic option of building the Docker container by the peer itself. As we have defined the &lt;code&gt;external-builder&lt;/code&gt;, the following order of scripts are executed.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;detect&lt;/code&gt; script simply evaluates whether the chaincode that is getting installed has the &lt;code&gt;type&lt;/code&gt; key of &lt;code&gt;metadata.json&lt;/code&gt; as a value &lt;code&gt;external&lt;/code&gt;. If that script fails then the peer considers that this external builder does not have to build the chaincode and iterates to other external builders until there are no more defined and fallback to the Docker building process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# The bin/detect script is responsible for determining whether or not a buildpack &lt;/span&gt;
&lt;span class="c"&gt;# should be used to build a chaincode package and launch it. &lt;/span&gt;
&lt;span class="c"&gt;# &lt;/span&gt;
&lt;span class="c"&gt;# The peer invokes detect with two arguments:&lt;/span&gt;
&lt;span class="c"&gt;# bin/detect CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# When detect is invoked, CHAINCODE_SOURCE_DIR contains the chaincode source and &lt;/span&gt;
&lt;span class="c"&gt;# CHAINCODE_METADATA_DIR contains the metadata.json file from the chaincode package installed to the peer. &lt;/span&gt;
&lt;span class="c"&gt;# The CHAINCODE_SOURCE_DIR and CHAINCODE_METADATA_DIR should be treated as read only inputs. &lt;/span&gt;
&lt;span class="c"&gt;# If the buildpack should be applied to the chaincode source package, detect must return an exit code of 0; &lt;/span&gt;
&lt;span class="c"&gt;# any other exit code will indicate that the buildpack should not be applied.&lt;/span&gt;

&lt;span class="nv"&gt;CHAINCODE_METADATA_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="c"&gt;# use jq to extract the chaincode type from metadata.json and exit with&lt;/span&gt;
&lt;span class="c"&gt;# success if the chaincode type is golang&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHAINCODE_METADATA_DIR&lt;/span&gt;&lt;span class="s2"&gt;/metadata.json"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/[{}]/''/g'&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt;&lt;span class="s2"&gt;"[,:}]"&lt;/span&gt; &lt;span class="s1"&gt;'{for(i=1;i&amp;lt;=NF;i++){if($i~/'&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="s1"&gt;'\042/){print $(i+1)}}}'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"external"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;detect&lt;/code&gt; script succeeds, then the &lt;code&gt;build&lt;/code&gt; script is called. This script should generate the artifacts or binaries if we were building the chaincode inside the peer, but as we want to have as external service, it is enough to simply copy the &lt;code&gt;connection.json&lt;/code&gt; file to the build output directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# The bin/build script is responsible for building, compiling, or transforming the contents &lt;/span&gt;
&lt;span class="c"&gt;# of a chaincode package into artifacts that can be used by release and run.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# The peer invokes build with three arguments:&lt;/span&gt;
&lt;span class="c"&gt;# bin/build CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR BUILD_OUTPUT_DIR&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# When build is invoked, CHAINCODE_SOURCE_DIR contains the chaincode source and &lt;/span&gt;
&lt;span class="c"&gt;# CHAINCODE_METADATA_DIR contains the metadata.json file from the chaincode package installed to the peer.&lt;/span&gt;
&lt;span class="c"&gt;# BUILD_OUTPUT_DIR is the directory where build must place artifacts needed by release and run. &lt;/span&gt;
&lt;span class="c"&gt;# The build script should treat the input directories CHAINCODE_SOURCE_DIR and &lt;/span&gt;
&lt;span class="c"&gt;# CHAINCODE_METADATA_DIR as read only, but the BUILD_OUTPUT_DIR is writeable.&lt;/span&gt;

&lt;span class="nv"&gt;CHAINCODE_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;CHAINCODE_METADATA_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;BUILD_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="c"&gt;#external chaincodes expect connection.json file in the chaincode package&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHAINCODE_SOURCE_DIR&lt;/span&gt;&lt;span class="s2"&gt;/connection.json"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHAINCODE_SOURCE_DIR&lt;/span&gt;&lt;span class="s2"&gt;/connection.json not found"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;#simply copy the endpoint information to specified output location&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$CHAINCODE_SOURCE_DIR&lt;/span&gt;/connection.json &lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/connection.json

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CHAINCODE_SOURCE_DIR&lt;/span&gt;&lt;span class="s2"&gt;/metadata"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nv"&gt;$CHAINCODE_SOURCE_DIR&lt;/span&gt;/metadata &lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/metadata
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, once the &lt;code&gt;build&lt;/code&gt; script completes, the &lt;code&gt;release&lt;/code&gt; script gets called. This script is responsible for providing the &lt;code&gt;connection.json&lt;/code&gt; to the peer by placing it in the release output directory. Hence, the peer now knows where to call the chaincode if some invocations of that chaincode are to be executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;# The bin/release script is responsible for providing chaincode metadata to the peer. &lt;/span&gt;
&lt;span class="c"&gt;# bin/release is optional. If it is not provided, this step is skipped. &lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# The peer invokes release with two arguments:&lt;/span&gt;
&lt;span class="c"&gt;# bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# When release is invoked, BUILD_OUTPUT_DIR contains the artifacts &lt;/span&gt;
&lt;span class="c"&gt;# populated by the build program and should be treated as read only input. &lt;/span&gt;
&lt;span class="c"&gt;# RELEASE_OUTPUT_DIR is the directory where release must place artifacts to be consumed by the peer.&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;BUILD_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;RELEASE_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# copy indexes from metadata/* to the output directory&lt;/span&gt;
&lt;span class="c"&gt;# if [ -d "$BUILD_OUTPUT_DIR/metadata" ] ; then&lt;/span&gt;
&lt;span class="c"&gt;#    cp -a "$BUILD_OUTPUT_DIR/metadata/"* "$RELEASE_OUTPUT_DIR/"&lt;/span&gt;
&lt;span class="c"&gt;# fi&lt;/span&gt;

&lt;span class="c"&gt;#external chaincodes expect artifacts to be placed under "$RELEASE_OUTPUT_DIR"/chaincode/server&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/connection.json &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
   &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RELEASE_OUTPUT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/chaincode/server
   &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/connection.json &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RELEASE_OUTPUT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/chaincode/server

   &lt;span class="c"&gt;#if tls_required is true, copy TLS files (using above example, the fully qualified path for these fils would be "$RELEASE_OUTPUT_DIR"/chaincode/server/tls)&lt;/span&gt;

   &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Building and deploying the External Chaincode
&lt;/h1&gt;

&lt;p&gt;Once we have the chaincodes installed in the peers, we can now build them and deploy them in our Kubernetes cluster. Let’s look at the changes we need to implement to the chaincodes.&lt;/p&gt;

&lt;p&gt;As the chaincodes do not vendor and include the modules needed currently, the imports have changed, so there is the need to import them and vendoring the modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/hyperledger/fabric-chaincode-go/shim"&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt; &lt;span class="s"&gt;"github.com/hyperledger/fabric-protos-go/peer"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to also define the &lt;code&gt;go.mod&lt;/code&gt; file to establish the version of the modules before building the code. The latest builds in the shim modules are needed to enable the External Chaincode property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;marbles&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="m"&gt;1.12&lt;/span&gt;

&lt;span class="n"&gt;require&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hyperledger&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fabric&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;chaincode&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200128192331&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;d899240a7ed&lt;/span&gt;
        &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hyperledger&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fabric&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;protos&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200124220212&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e9cfc186ba7b&lt;/span&gt;
        &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200202094626&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;16171245&lt;/span&gt;&lt;span class="n"&gt;cfb2&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
        &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200212091648&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="n"&gt;a6c2dcc1e4&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
        &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.3.2&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
        &lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;genproto&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200218151345&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dad8c97a84f5&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other change is the &lt;code&gt;Chaincode Server&lt;/code&gt; property which listens to a particular address and port that we want to establish. As we might want to change them by using Kubernetes yaml descriptors, we are going to use the os module to get the value of the address and the chaincode code package identifier (&lt;strong&gt;CCID&lt;/strong&gt;). By doing this we can deploy the same image of the code but changing the parameters as needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;shim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChaincodeServer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CCID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CHAINCODE_CCID"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CHAINCODE_ADDRESS"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleChaincode&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;TLSProps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;shim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TLSProperties&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Disabled&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Start the chaincode external server&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error starting Marbles02 chaincode: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are now ready to build the chaincode container using the following &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# This image is a microservice in golang for the Marbles chaincode&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; golang:1.14.6-alpine AS build&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./ /go/src/github.com/marbles&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /go/src/github.com/marbles&lt;/span&gt;

&lt;span class="c"&gt;# Build application&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; chaincode &lt;span class="nt"&gt;-v&lt;/span&gt; .

&lt;span class="c"&gt;# Production ready image&lt;/span&gt;
&lt;span class="c"&gt;# Pass the binary to the prod image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:3.11 as prod&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /go/src/github.com/marbles/chaincode /app/chaincode&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 1000&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ./chaincode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The chaincode is built using a golang alpine image. Once the building stage is complete, the binary is transferred to a bare alpine image for a smaller and secure image. Execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t chaincode/marbles:1.0 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything goes right, you should have the image ready to be deployed. Modify the files of the chaincode deployment ( &lt;code&gt;org1-chaincode-deployment.yaml&lt;/code&gt; and &lt;code&gt;org2-chaincode-deployment.yaml&lt;/code&gt;) the &lt;strong&gt;CHAINCODE_CCID&lt;/strong&gt; variable to the values you got before when installing the chaincode respectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#---------------- Chaincode Deployment ---------------------&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaincode-marbles-org1&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hyperledger&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaincode-marbles-org1&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaincode-marbles-org1&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Recreate&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaincode-marbles-org1&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaincode/marbles:1.0&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chaincode-marbles-org1&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CHAINCODE_CCID&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;marbles:d8140fbc1a0903bd88611a96c5b0077a2fdeef00a95c05bfe52e207f5f9ab79d"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CHAINCODE_ADDRESS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0:7052"&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7052&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, deploy them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl create -f chaincode/k8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service and deployments will be deployed in the same k8s namespace as the other workload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl get pods -n hyperledger
NAME                                      READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-tx59g                  1/1     Running   0          19h
ca-org2-7454f69c48-nfzsq                  1/1     Running   0          19h
chaincode-marbles-org1-6fc8858855-wdz7z   1/1     Running   0          20m
chaincode-marbles-org2-77bf56fdfb-6cdfm   1/1     Running   0          14m
cli-org1-589944999c-cvgbx                 1/1     Running   0          19h
cli-org2-656cf8dd7c-kcxd7                 1/1     Running   0          19h
orderer0-5844bd9bcc-6td8c                 1/1     Running   0          46h
orderer1-75d8df99cd-6vbjl                 1/1     Running   0          46h
orderer2-795cf7c4c-6lsdd                  1/1     Running   0          46h
peer0-org1-5bc579d766-kq2qd               1/1     Running   0          19h
peer0-org2-77f58c87fd-sczp8               1/1     Running   0          19h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have to approve the chaincodes for each organization. This is a new feature of the chaincode lifecycle process, each organization has to agree to approve a new definition of a chaincode. We are going to approve the marble chaincode definition for &lt;strong&gt;org1&lt;/strong&gt;. Execute this command inside the &lt;strong&gt;org1&lt;/strong&gt; cli pod, remember to change the &lt;strong&gt;CHAINCODE_CCID&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
2020-03-08 10:02:46.192 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 001 txid [4d81ea5fd494e9717a0c860812d2b06bc62e4fc6c4b85fa6c3a916eee2c78e85] committed with status (VALID)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the state of approvals throughout the entire network by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-required --sequence 1 -o -orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
Chaincode definition for chaincode 'marbles', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
org1MSP: true
org2MSP: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s approve for &lt;strong&gt;org2&lt;/strong&gt;. Execute this command inside the org2 cli pod, remember to change the &lt;strong&gt;CHAINCODE_CCID&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:25a9f6fe26161d29af928228ca1db0c41892e26e46335c84952336ee26d1fd93 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
2020-03-08 10:26:43.992 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 001 txid [74a89f3c93c10f14c626bd4d6cb654b37889908c9e6f7b983d2cad79f1e82267] committed with status (VALID)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check again the commit readiness of the chaincode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-required --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
Chaincode definition for chaincode 'marbles', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
org1MSP: true
org2MSP: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have all the approvals of all the organizations, let’s commit the definition of this chaincode in the channel. You can do this operation on any of the peers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer lifecycle chaincode commit -o orderer0:7050 --channelID mychannel --name marbles --version 1.0 --sequence 1 --init-required --tls true --cafile $ORDERER_CA --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt

### Should print a similar output
2020-03-08 14:13:49.516 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 001 txid [568cb81f821698025bbc61f4c6cd3b4baf1aea632e1e1a8cfdf3ec3902d1c6bd] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:13:49.533 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 002 txid [568cb81f821698025bbc61f4c6cd3b4baf1aea632e1e1a8cfdf3ec3902d1c6bd] committed with status (VALID) at peer0-org2:7051
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the chaincode definition added to the channel and ready to be invoked and make queries against it! 😄&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing the External Chaincode
&lt;/h1&gt;

&lt;p&gt;We can test the chaincodes making invoke and query commands from the cli pod. These commands are not modified by the lifecycle chaincode process and can be called as the chaincodes in version 1.x of Hyperledger Fabric. First, let’s create some marbles in the ledger. Execute the following command on one cli pod, either &lt;strong&gt;org1&lt;/strong&gt; or &lt;strong&gt;org2&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer chaincode invoke -o orderer0:7050 --isInit --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses 
peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer
0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble
","marble1","blue","35","tom"]}' --waitForEvent

### Should print a similar output
2020-03-08 14:23:03.569 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 001 txid [83aeeaac47cf6302bc139addc4aa38116a40eaff788846d87cc815d2e1318f44] committed with status (VALID) at peer0-org2:7051
2020-03-08 14:23:03.575 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 002 txid [83aeeaac47cf6302bc139addc4aa38116a40eaff788846d87cc815d2e1318f44] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:23:03.576 UTC [chaincodeCmd] chaincodeInvokeOrQuery -&amp;gt; INFO 003 Chaincode invoke successful. result: status:200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initiate the ledger, the --isInit will call to the legacy &lt;code&gt;init&lt;/code&gt; function to start the ledger. Now create the first marble:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer chaincode invoke -o orderer0:7050 --isInit --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble","marble1","red","45","tom"]}' --waitForEvent

### Should print a similar output
2020-03-08 14:23:40.404 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 001 txid [8391f9f8ea84887a56f99e4dc4501eaa6696cd7bd6c524e4868bd6cfd5b85e78] committed with status (VALID) at peer0-org2:7051
2020-03-08 14:23:40.434 UTC [chaincodeCmd] ClientWait -&amp;gt; INFO 002 txid [8391f9f8ea84887a56f99e4dc4501eaa6696cd7bd6c524e4868bd6cfd5b85e78] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:23:40.434 UTC [chaincodeCmd] chaincodeInvokeOrQuery -&amp;gt; INFO 003 Chaincode invoke successful. result: status:200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first c&lt;/p&gt;

&lt;p&gt;Retrieve information from marble1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble1"]}'

{"docType":"marble","name":"marble1","color":"red","size":45,"owner":"tom"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many example commands you can execute with this chaincode, just check the source code of the chaincode for more examples.&lt;/p&gt;

&lt;p&gt;You can also check the logs of the chaincode containers by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl logs chaincode_pod_name -n hyperledger

### Should print a similar output
invoke is running initMarble
- start init marble
- end init marble
invoke is running initMarble
- start init marble
- end init marble
invoke is running readMarble
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Bonus Track! ContractApi based Chaincodes with External Chaincodes feature
&lt;/h1&gt;

&lt;p&gt;As a new addition that we have been playing lately, we can now deploy external chaincodes with the new ContractApi introduced in version 2.0, which makes it even more easy to develop chaincodes. We will deploy the &lt;a href="https://github.com/hyperledger/fabric-samples/blob/master/chaincode/fabcar/go/fabcar.go"&gt;fabcar&lt;/a&gt; chaincode, you can find the original here. The modified one would be pushed in the repo under the folder named &lt;code&gt;fabcar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will need to do add the new shim api which allows to add the External Chaincode server interface that allows the external communication with the peer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/hyperledger/fabric-chaincode-go/shim"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/hyperledger/fabric-contract-api-go/contractapi"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// SmartContract provides functions for managing a car&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SmartContract&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;contractapi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contract&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Car describes basic details of what makes up a car&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Car&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Make&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"make"`&lt;/span&gt;
    &lt;span class="n"&gt;Model&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"model"`&lt;/span&gt;
    &lt;span class="n"&gt;Colour&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"colour"`&lt;/span&gt;
    &lt;span class="n"&gt;Owner&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"owner"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// QueryResult structure used for handling result of query&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;QueryResult&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Key&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"Key"`&lt;/span&gt;
    &lt;span class="n"&gt;Record&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Car&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Main function to start the external chaincode server&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;contractapi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewChaincode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmartContract&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error starting a new ContractApi Chaincode:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;shim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChaincodeServer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;CCID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CHAINCODE_CCID"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CHAINCODE_ADDRESS"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;TLSProps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;shim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TLSProperties&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Disabled&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Start the chaincode external server&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error starting FabCar chaincode server:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Succesfully started new Fabcar Chaincode server with the new ContractApi"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;go.mod&lt;/code&gt; file would need to import these two modules as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fabcar&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="m"&gt;1.14&lt;/span&gt;

&lt;span class="n"&gt;require&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hyperledger&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fabric&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;chaincode&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200424173110&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d7076418f212&lt;/span&gt;
        &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hyperledger&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fabric&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;contract&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="m"&gt;.1.0&lt;/span&gt;
        &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200202094626&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;16171245&lt;/span&gt;&lt;span class="n"&gt;cfb2&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
        &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200212091648&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="n"&gt;a6c2dcc1e4&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
        &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.3.2&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
        &lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;genproto&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="m"&gt;.0.0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;20200218151345&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dad8c97a84f5&lt;/span&gt; &lt;span class="c"&gt;// indirect&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that would be all modifications needed in order to make it work! The instructions to install it works just the same but with the word fabcar instead of marbles. The only difference is that there is no need for &lt;code&gt;--init-required&lt;/code&gt; or &lt;code&gt;--isInit&lt;/code&gt; flag in the &lt;code&gt;approveformyorg&lt;/code&gt; , &lt;code&gt;commit&lt;/code&gt; and &lt;code&gt;invoke&lt;/code&gt; commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;peer lifecycle chaincode approveformyorg --channelID mychannel --name fabcar --version 1.0 --package-id fabcar:005c35f4f172c056723eca09d41e8048e0beaa2712d920c19af837640df7e2aa --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA

peer lifecycle chaincode approveformyorg --channelID mychannel --name fabcar --version 1.0 --package-id fabcar:61ab817a6ad76098d340952e5d8e928d9c5ddff1a53341dc8d0c64b4345564b0 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --sequence 1 -o -orderer0:7050 --tls --cafile $ORDERER_CA

peer lifecycle chaincode commit -o orderer0:7050 --channelID mychannel --name fabcar --version 1.0 --sequence 1 --tls true --cafile $ORDERER_CA --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt

peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n fabcar --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["InitLedger"]}' --waitForEvent

peer chaincode query -C mychannel -n fabcar -c '{"Args":["QueryAllCars"]}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would also find the original implementation of this same chaincode with the External Chaincode feature by the Hyperledger team in &lt;a href="https://github.com/hyperledger/fabric-samples/tree/master/chaincode/fabcar/external"&gt;their github repo&lt;/a&gt;. Not many differences are between their implementation and ours, so we assume that this is the proper way to implement this contract based chaincodes with external feature.&lt;/p&gt;

&lt;h1&gt;
  
  
  Future work and improvements
&lt;/h1&gt;

&lt;p&gt;There are some improvements that can be made and we are happy to receive feedback from the community to improve these External Chaincodes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;External Builders definition as environment variables rather than configmap&lt;/strong&gt;. Although it works this way, we would like to define the External Builders in the environment variables as other options. We tried to define the external builders as environment variables but since the ExternalBuilders configurations is expected as array and the environment variables only accept strings, we were having many errors. &lt;strong&gt;UPDATE 2&lt;/strong&gt;: &lt;em&gt;Many of you have reported many problems with externalbuilder definition not being executed succesfully or properly detected. This was caused mainly for permissions on the scripts folder (execute permission required not enabled after cloning from GitHub). For ease of use, the buildpack scripts have now been included as a configmap and attached in the peer pods with greater kubernetes integration.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Endorsement Policy failures&lt;/strong&gt;: We had to disable the Endorsement and the Lifecycle Endorsment policies due to many endorsement policy failures when committing the chaincode definition on the channel. As this might need to have some better understanding and definition of the policies in version 2.0, we did not have enough time to configure it properly. &lt;strong&gt;UPDATE 1&lt;/strong&gt;: &lt;em&gt;This has now been solved and the article has been updated with the new requirements for making the endorsement policies and lifecycle endorsement policies coded in the genesis block.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual changes on the address configuration of the chaincode&lt;/strong&gt;. The address value of the &lt;code&gt;connection.json&lt;/code&gt; file needs to be changed every time we have a new organization. And also can change if we have multiple endorser peers for each organisation. There could be some interesting pipelines to help support the deployment of these type of chaincodes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for taking a look into it!&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>kubernetes</category>
      <category>docker</category>
      <category>hyperledger</category>
    </item>
  </channel>
</rss>
