Contents


Blockchain chaincode for Java developers

How to write chaincode for Hyperledger Fabric v0.6 using the Java language

Comments

You've probably heard about blockchain, but maybe you're not sure how it applies to you as a Java™ developer. This tutorial will clear up any confusion. In a step-by-step approach, I'll show you how to use the Hyperledger Fabric v0.6 to build, run, and execute smart contracts, or chaincode, written in the Java language. You'll install tools, define your local blockchain network, and finally, build and run a chaincode smart contract.

For an overview of blockchain, see "What is blockchain? A Primer on Distributed Ledger Technology" on the developerWorks blog.

Prerequisites

For this tutorial, I'll assume that you have the following prerequisites:

  • You've heard of blockchain or the Hyperledger Fabric framework
  • You have intermediate Java programming knowledge and experience with both the language and platform
  • You are familiar with or (ideally) proficient in using:
    • Eclipse IDE
    • Docker and Docker Compose
    • Gradle
    • Linux command line
    • SoapUI or another HTTP client software, such as Postman

You should also be comfortable installing software on your computer with minimal guidance. In the interest of space, I'm not including detailed installation instructions for all the software you need; the websites where you can obtain the software provide installation instructions.

Before we dive into the meat of the tutorial, I want to talk a little about blockchain.

Blockchain basics

A lot of hype surrounds blockchain, but it's well deserved. Not only is the technology itself cool, it's disruptive and has the potential to revolutionize the way business is done on the Internet.

How? Well, let's think about the fundamental attributes of a successful business deal:

  • Trust: We have a deal, but can I really trust you to honor it (or you me)?
  • Transparency: Allows a look "behind the curtain" (which can both build trust and lessen the need for it).
  • Accountability: Defines criteria to determine whether or not all parties agree that the deal has been honored.

The health of any business relationship between two or more parties will mean varying levels of the three attributes above (for example, more trust means less transparency required, and vice versa), but some of all of them must be present, or there will be problems.

Blockchain technology is rapidly making its way to a software development project near you. Will you be ready?

How does blockchain help? First of all, through the use of a common framework, business partners can establish an upfront network of trust. Then, through the use of a ledger that is visible to all business parties, blockchain provides transparency. Finally, through the use of consensus from all parties in the form of smart contracts (or chaincode), there is accountability.

So what does this mean for you as a Java developer?

The rapid growth of the Hyperledger community and the Hyperledger Fabric means that blockchain technology is rapidly making its way to a software development project near you. Will you be ready?

The blockchain technology landscape

Sometimes development technology can get in the way of solving the business problem. My main goal is in this tutorial is to show you how to write Java chaincode, so I've chosen the simplest development stack for that purpose.

That said, there are other choices for the components of the stack. For this tutorial, I'll use Docker as the network container environment, but another option is Vagrant with VirtualBox. If you've never used Vagrant, you should at least try it out.

Whereas Docker is a container environment, Vagrant uses virtualization. When combined with VirtualBox, a virtualization environment provides a different level of control over the computing environment that some developers prefer (which makes it an ideal choice for fabric developers).

If you want to learn more about containerization versus virtualization, check out "What is Docker? A Primer on the Benefits of Containers for Applications" on the developerWorks blog.

IBM® Bluemix® is a choice for developers who just want to write code and not have to worry about containers, virtualization, or any infrastructure, for that matter. And although Bluemix supports running a full IBM Blockchain network, it does not yet support chaincode development using the Java language. I expect this to change very soon, so stay tuned.

If you are getting the impression that the blockchain technology landscape is very fluid at the moment, you're correct. However, this means you're getting into blockchain and chaincode at just the right time: on the ground floor. As this technology matures, your investment in learning it at this early stage will pay handsome dividends down the road.

Blockchain is one of those disruptive technologies that has the potential to revolutionize the way everyone does business. Not just B2B, but B2C, and eventually C2C. This is a very exciting time, indeed.

Let's get started!

Set up your development environment

In order to run chaincode, you first need to set up your development environment.

Once you've completed this section, you'll be ready to run one of the Hyperledger Java chaincode examples, where you'll deploy and invoke transactions on real chaincode. After that, I'll show you how to write a new chaincode program from scratch (well, almost).

In this section you will:

  1. Set up the network environment — to run your local blockchain network.
  2. Install the build software — to build your chaincode.
  3. Install an HTTP client — to invoke transactions on your chaincode.
  4. Start the blockchain network.
  5. Build the Java shim client JAR.

I won't lie to you; there is quite a bit of setup work to be done in order to write chaincode. But if you follow these instructions and apply a little diligence, it will be worth it.

1

Set up the network environment

In this tutorial, you'll use Docker, along with pre-built blockchain network component images from Docker Hub, to run your local blockchain network. You could build the fabric from scratch if you wanted to (it's open source, after all), but at this stage, it's easier to use the pre-built Hyperledger Fabric images available in Docker Hub.

As I mentioned in the introduction, another option (and one you may see in the Hyperledger docs) is to use Vagrant and VirtualBox. Vagrant is a great choice for fabric developers, though as chaincode developers, we're more concerned with building, running, and testing our chaincode than working with the fabric itself.

If you already have Docker version 1.12 or higher installed, you can skip to the next section ("Install the build software") In the instructions that follow, I'll assume you do not have Docker installed (that is, you are not upgrading from a previous version of Docker). The Docker installation will also install Docker Compose, a tool for defining and running applications that require multiple containers, as the local Hyperledger blockchain network you will run in this tutorial does.

Install Docker

Installation instructions for Mac, Windows, and Linux can be found here:

Install Docker on Mac, Windows, and Linux

Verify Docker installation

To test your Docker installation, open a terminal window (or command prompt on Windows) and type the following commands:

                    docker -v
                    docker-compose -v

You should get output like this:

                    $ docker -v
                    Docker version 1.13.1, build 092cba3
                    $ docker-compose -v
                    docker-compose version 1.11.1, build 7c5d5e4

If you want to see Docker in action, you can run the hello-world image like this:

                    $ docker run hello-world
                    Unable to find image 'hello-world:latest' locally
                    latest: Pulling from library/hello-world
                    78445dd45222: Pull complete 
                    Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
                    Status: Downloaded newer image for hello-world:latest
                    
                    Hello from Docker!
                    This message shows that your installation appears to be working correctly.
                    
                    To generate this message, Docker took the following steps:
                     1. The Docker client contacted the Docker daemon.
                     2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
                     3. The Docker daemon created a new container from that image which runs the
                        executable that produces the output you are currently reading.
                     4. The Docker daemon streamed that output to the Docker client, which sent it
                        to your terminal.
                    
                    To try something more ambitious, you can run an Ubuntu container with:
                     $ docker run -it ubuntu bash
                    
                    Share images, automate workflows, and more with a free Docker ID:
                     https://cloud.docker.com/
                    
                    For more examples and ideas, visit:
                     https://docs.docker.com/engine/userguide/
2

Install the build software

For the build system, the Hyperledger Fabric uses Gradle, and you will use that for this tutorial as well. Gradle is a build automation system that combines simple syntax to specify build components, along with the best features of Apache Ant and Apache Maven to create a powerful build system that's easy to use. It's no wonder so many developers are switching their projects over to Gradle.

Read more about Gradle (and some of its high-profile users) on the Gradle main page.

Install Gradle

To install Gradle, follow the instructions here:

Install Gradle on Mac, Windows, and Linux

Verify Gradle installation

To verify your Gradle installation, open a terminal window and execute this command:

                    gradle -v

You should see output like this:

                $ gradle -v
                
                ------------------------------------------------------------
                Gradle 3.3
                ------------------------------------------------------------
                
                Build time:   2017-01-03 15:31:04 UTC
                Revision:     075893a3d0798c0c1f322899b41ceca82e4e134b
                
                Groovy:       2.4.7
                Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
                JVM:          1.8.0_102 (Oracle Corporation 25.102-b14)
                OS:           Mac OS X 10.12.3 x86_64
3

Install an HTTP client

Next up is the HTTP client software, which allows your chaincode to communicate with the Hyperledger blockchain fabric's REST interface. Your browser can issue an HTTP GET, but to interact with the fabric you need to be able to POST messages. This means you need an HTTP client.

The HTTP client I've chosen for this tutorial is SoapUI, which provides a free community edition that's powerful, easy to use, and contains many features.

Install SoapUI

To install SoapUI, follow the instructions here:

Install SoapUI for Mac OS, Windows, and Linux

Verify SoapUI installation

To verify that SoapUI is installed, start the application on your computer. On Mac OS, SoapUI should open to the SoapUI Starter Page, shown in Figure 1.

Figure 1. SoapUI on Mac OS X
SoapUI on Mac OS X
SoapUI on Mac OS X
4

Start the blockchain network

Now that you have installed the necessary software to develop and test your chaincode, it's time to start your local blockchain network. The first step is to define the network's configuration.

First, create a directory that will serve as the root of all of the source code you'll use for chaincode development. In this tutorial I'll use ~/home/mychaincode (or C:\home\chaincode on Windows).

Next, set the GOPATH environment variable to this path. We won't be compiling any Go code, nor building Golang packages or other binaries, but Golang terminology is baked into Hyperledger, so it's a good idea to get comfortable with thinking in terms of the Go language and GOPATH.

On Linux, you would execute this command:

                export GOPATH=~/home/mychaincode

Or on Windows, you might use something like:

                SET GOPATH=C:\home\mychaincode

Next, you must tell Docker Compose how to compose and run the blockchain peer network. The definition of the network is in YAML, and you should name it docker-compose.yml. You can call the file something else, but when you start Docker Compose, you must specify the -f flag. I recommend sticking with the default, which is docker-compose.yml.

Create the docker-compose.yml file in the root of your GOPATH. Paste in the following contents:

                membersrvc:
                  image: hyperledger/fabric-membersrvc
                  ports:
                    - "7054:7054"
                  command: membersrvc
                vp0:
                  image: hyperledger/fabric-peer
                  ports:
                    - "7050:7050"
                    - "7051:7051"
                    - "7053:7053"
                  environment:
                    - CORE_PEER_ADDRESSAUTODETECT=true
                    - CORE_VM_ENDPOINT=unix:///var/run/docker.sock
                    - CORE_LOGGING_LEVEL=DEBUG
                    - CORE_PEER_ID=vp0
                    - CORE_PEER_PKI_ECA_PADDR=membersrvc:7054
                    - CORE_PEER_PKI_TCA_PADDR=membersrvc:7054
                    - CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054
                    - CORE_SECURITY_ENABLED=false
                    - CORE_SECURITY_ENROLLID=test_vp0
                    - CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT
                  links:
                    - membersrvc
                  command: sh -c "sleep 5; peer node start --peer-chaincodedev"

There is a lot going on here, much of which is beyond the scope of this tutorial, but I want to explain a few things.

  • This file tells Docker Compose to define two services:
    • membersrvc: The member services node that provides membership services, specifically a certificate authority (CA), which is responsible for handling all of the cryptographic logistics (such as issuing and revoking certificates). The pre-built Docker image you'll use for this is called hyperledger/fabric-membersrvc.
    • vp0: The lone validating peer node in the network. For development purposes, we don't need an extravagant validating peer network; a single peer will do. The pre-built Docker image you will use for this is called hyperledger/fabric-peer.
  • A number of environment variables are set by the vp0 peer. Notice the CORE_LOGGING_LEVEL variable is set to DEBUG. This produces a large amount of output, which can be handy at times. However, if you want less output, change the level to INFO. See "Logging Control" in the Hyperledger Setup docs for more information about the logging levels.

    More information can be found about the Docker Compose YML file definition on Docker's website.

Next, notice that the CORE_SECURITY_ENABLED value is false. This means the fabric will not require you to send any type of end-user credentials. Security is beyond the scope of this tutorial, but if you are interested in learning more, you can check out this note on security functionality for your chaincode requests.

Finally, a word of caution: Changing any of these values from their defaults (especially the port values) may cause the examples in this tutorial to fail to work. A blockchain network is a set of distributed software components that require precisely coordinated communication. I highly recommend you do not change the port values from their default values until you understand how all the components of the fabric interoperate.

Now that the blockchain network definition is in place, you're ready to start your local blockchain network. To do this, run Docker Compose. Navigate to your $GOPATH and execute this command:

                docker-compose up

You should get output in the terminal window like this:

                $ docker-compose up
                .
                .
                Pulling membersrvc (hyperledger/fabric-membersrvc:latest)...
                latest: Pulling from hyperledger/fabric-membersrvc
                .
                .
                Status: Downloaded newer image for hyperledger/fabric-membersrvc:latest
                Pulling vp0 (hyperledger/fabric-peer:latest)...
                latest: Pulling from hyperledger/fabric-peer
                .
                .
                Status: Downloaded newer image for hyperledger/fabric-peer:latest
                Creating mychaincode_membersrvc_1
                Creating mychaincode_vp0_1
                Attaching to mychaincode_membersrvc_1, mychaincode_vp0_1
                vp0_1         | 19:30:03.773 [logging] LoggingInit -> DEBU 001 Setting default logging level to DEBUG for command 'node'
                vp0_1         | 19:30:03.773 [nodeCmd] serve -> INFO 002 Running in chaincode development mode
                .
                .
                .
                vp0_1         | 19:30:04.146 [peer] chatWithSomePeers -> DEBU 07c Starting up the first peer of a new network
                vp0_1         | 19:30:04.146 [consensus/statetransfer] verifyAndRecoverBlockchain -> DEBU 07d Validating existing blockchain, highest validated block is 0, valid through 0
                vp0_1         | 19:30:04.146 [consensus/statetransfer] blockThread -> INFO 07e Validated blockchain to the genesis block
                vp0_1         | 19:30:04.146 [consensus/handler] 1 -> DEBU 07f Starting up message thread for consenter
                vp0_1         | 19:30:04.146 [nodeCmd] serve -> INFO 080 Starting peer with ID=name:"vp0" , network ID=dev, address=172.17.0.3:7051, rootnodes=, validator=true
                vp0_1         | 19:30:04.146 [rest] StartOpenchainRESTServer -> INFO 081 Initializing the REST service on 0.0.0.0:7050, TLS is disabled.
                vp0_1         | 19:30:04.147 [peer] ensureConnected -> DEBU 082 Starting Peer reconnect service (touch service), with period = 6s
                .
                .

This output tells you the network is up and running, and ready to accept chaincode registration requests.

Note: The highlighted lines should only appear the first time you run your blockchain network, because Docker has to download the images from Docker Hub. Once they are downloaded to your computer, Docker will only pull them if the images from Docker Hub are newer than the ones you have on your computer.

Now you're ready to build the Java shim client JAR, which allows your Java language chaincode to communicate with the Hyperledger Fabric framework.

5

Build the Java shim client JAR

Before you can run the chaincode examples, you need to get the latest source code from Hyperledger's GitHub repository.

First, you will need to clone the Hyperledger Fabric on your local machine in order to build your chaincode (Note: This is a temporary measure; at some point the Java shim client JAR should be accessible from the central Maven repository).

Note: Recall from earlier that you set your GOPATH to ~/home/mychaincode on Linux (or Mac) or C:\home\mychaincode on Windows.

Execute this command to create the directory structure the fabric build scripts expect:

mkdir -p $GOPATH/src/github.com/hyperledger

Next, navigate to the bottom of the new directory structure you created:

                cd $GOPATH/src/github.com/hyperledger

From here you need to retrieve the Hyperledger source code so you can build the Java shim client JAR.

Figure 2. Hyperledger GitHub mirror
Hyperledger GitHub mirror
Hyperledger GitHub mirror

There are two ways to access the Hyperledger source.

  • Without git:

    Navigate to the Hyperledger GitHub mirror and click on the Clone or download button, then Download ZIP (see Figure 2). A ZIP file called fabric-master.zip will be downloaded to your computer, which you can extract to $GOPATH/src/github.com/hyperledger. Note: make sure to change the name of the root directory from fabric-master to fabric when you extract the file.

  • With git:

    Navigate to $GOPATH/src/github.com/hyperledger, copy the URL from the text field in the "Clone with HTTPS" box (see the arrow in Figure 2), and execute this command using the copied URL:

                git clone https://github.com/hyperledger/fabric.git

You should see terminal window output like this from the git command:

                $ git clone https://github.com/hyperledger/fabric.git
                Cloning into 'fabric'...
                remote: Counting objects: 26976, done.
                remote: Compressing objects: 100% (406/406), done.
                remote: Total 26976 (delta 172), reused 0 (delta 0), pack-reused 26558
                Receiving objects: 100% (26976/26976), 43.68 MiB | 4.85 MiB/s, done.
                Resolving deltas: 100% (15114/15114), done.

Now you're ready to build the Java chaincode shim client JAR. Navigate to $GOPATH/src/github.com/hyperledger/fabric/core/chaincode/shim/java and run these two commands:

                gradle -b build.gradle clean
                gradle -b build.gradle build

The Gradle build output should look like this:

                $ cd $GOPATH/src/github.com/hyperledger/fabric/core/chaincode/shim/java
                $ gradle -b build.gradle clean
                Starting a Gradle Daemon (subsequent builds will be faster)
                :core:chaincode:shim:java:clean
                
                BUILD SUCCESSFUL
                
                Total time: 5.422 secs
                $ gradle -b build.gradle build
                :core:chaincode:shim:java:copyProtos UP-TO-DATE
                :core:chaincode:shim:java:extractIncludeProto
                :core:chaincode:shim:java:extractProto UP-TO-DATE
                :core:chaincode:shim:java:generateProto UP-TO-DATE
                :core:chaincode:shim:java:compileJava
                :core:chaincode:shim:java:processResources
                :core:chaincode:shim:java:classes
                :core:chaincode:shim:java:jar
                :core:chaincode:shim:java:assemble
                :core:chaincode:shim:java:extractIncludeTestProto
                :core:chaincode:shim:java:extractTestProto UP-TO-DATE
                :core:chaincode:shim:java:generateTestProto UP-TO-DATE
                :core:chaincode:shim:java:compileTestJava UP-TO-DATE
                :core:chaincode:shim:java:processTestResources UP-TO-DATE
                :core:chaincode:shim:java:testClasses UP-TO-DATE
                :core:chaincode:shim:java:test UP-TO-DATE
                :core:chaincode:shim:java:check UP-TO-DATE
                :core:chaincode:shim:java:build
                :core:chaincode:shim:java:copyToLib
                :core:chaincode:shim:java:generatePomFileForMavenJavaPublication
                :core:chaincode:shim:java:publishMavenJavaPublicationToMavenLocal
                :core:chaincode:shim:java:publishToMavenLocal
                
                BUILD SUCCESSFUL
                
                Total time: 4.521 secs

The last thing the build does is add the shim client JAR to your local Maven repository. At this point, you're ready to build your chaincode. Unless you update your fabric source code at some point in the future, or just want to rebuild the shim client JAR again for some reason, you won't have to run the Java shim client JAR build again.

Deploy and run a Java chaincode example

Now that you've defined and started your local blockchain network, and have built and installed the Java shim client JAR to your local Maven repository, you're ready to build, register, and invoke transactions on one of the Java chaincode examples that ship with the Hyperledger Fabric that you downloaded earlier.

Here are the steps you'll follow:

  1. Build the example using Gradle.
  2. Register the example with the validating peer network, by running a script that is created for you by the Gradle build.
  3. Deploy the example to the local blockchain network using SoapUI.
  4. Invoke transactions on the example chaincode using SoapUI.
1

Build the example

Navigate to the $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example directory.

Next, launch the Gradle build via the command line using this command:

gradle -b build.gradle build

You should see output like this:

                $ cd GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example
                $ gradle -b build.gradle build
                Starting a Gradle Daemon (subsequent builds will be faster)
                :examples:chaincode:java:Example:compileJava
                :examples:chaincode:java:Example:processResources UP-TO-DATE
                :examples:chaincode:java:Example:classes
                :examples:chaincode:java:Example:jar
                :examples:chaincode:java:Example:startScripts
                :examples:chaincode:java:Example:distTar
                :examples:chaincode:java:Example:distZip
                :examples:chaincode:java:Example:assemble
                :examples:chaincode:java:Example:compileTestJava UP-TO-DATE
                :examples:chaincode:java:Example:processTestResources UP-TO-DATE
                :examples:chaincode:java:Example:testClasses UP-TO-DATE
                :examples:chaincode:java:Example:test UP-TO-DATE
                :examples:chaincode:java:Example:check UP-TO-DATE
                :examples:chaincode:java:Example:build
                :examples:chaincode:java:Example:copyToLib
                
                BUILD SUCCESSFUL
                
                Total time: 6.935 secs

The build creates a standalone distribution that's located within the directory build/distributions in two forms: a TAR file and a ZIP file, and each of these files contains everything you need to run the chaincode, including a script to drive it called Example.

The Example chaincode is now ready to be registered with the local blockchain network.

2

Register the example

Make sure your local blockchain network is running. If not, you'll need to start it up. See the section titled "Start the blockchain network" if you need a refresher.

If you're not already there, navigate to $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example.

Next, extract Example.zip (or Example.tar) in the build/distributions directory:

                $ cd $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example
                $ cd build/distributions/
                $ unzip Example.zip 
                Archive:  Example.zip
                  inflating: Example/lib/chaincode.jar  
                  inflating: Example/lib/grpc-all-0.13.2.jar  
                  inflating: Example/lib/commons-cli-1.3.1.jar  
                  inflating: Example/lib/shim-client-1.0.jar  
                  inflating: Example/lib/grpc-netty-0.13.2.jar  
                  inflating: Example/lib/grpc-auth-0.13.2.jar  
                  inflating: Example/lib/grpc-protobuf-nano-0.13.2.jar  
                  inflating: Example/lib/grpc-core-0.13.2.jar  
                  inflating: Example/lib/grpc-protobuf-0.13.2.jar  
                  inflating: Example/lib/grpc-okhttp-0.13.2.jar  
                  inflating: Example/lib/grpc-stub-0.13.2.jar  
                  inflating: Example/lib/protobuf-java-3.0.0.jar  
                  inflating: Example/lib/netty-tcnative-boringssl-static-1.1.33.Fork21-osx-x86_64.jar  
                  inflating: Example/lib/netty-codec-http2-4.1.0.CR3.jar  
                  inflating: Example/lib/google-auth-library-oauth2-http-0.3.0.jar  
                  inflating: Example/lib/guava-18.0.jar  
                  inflating: Example/lib/protobuf-javanano-3.0.0-alpha-5.jar  
                  inflating: Example/lib/jsr305-3.0.0.jar  
                  inflating: Example/lib/okio-1.6.0.jar  
                  inflating: Example/lib/okhttp-2.5.0.jar  
                  inflating: Example/lib/netty-codec-http-4.1.0.CR3.jar  
                  inflating: Example/lib/netty-handler-4.1.0.CR3.jar  
                  inflating: Example/lib/google-auth-library-credentials-0.3.0.jar  
                  inflating: Example/lib/google-http-client-1.19.0.jar  
                  inflating: Example/lib/google-http-client-jackson2-1.19.0.jar  
                  inflating: Example/lib/netty-codec-4.1.0.CR3.jar  
                  inflating: Example/lib/netty-buffer-4.1.0.CR3.jar  
                  inflating: Example/lib/netty-transport-4.1.0.CR3.jar  
                  inflating: Example/lib/httpclient-4.0.1.jar  
                  inflating: Example/lib/jackson-core-2.1.3.jar  
                  inflating: Example/lib/netty-common-4.1.0.CR3.jar  
                  inflating: Example/lib/netty-resolver-4.1.0.CR3.jar  
                  inflating: Example/lib/httpcore-4.0.1.jar  
                  inflating: Example/lib/commons-logging-1.1.1.jar  
                  inflating: Example/lib/commons-codec-1.3.jar  
                  inflating: Example/bin/Example     
                  inflating: Example/bin/Example.bat

"Why so many files?" you may wonder. The distribution contains everything you need to run the chaincode standalone (in its own process), along with all dependent JARs.

To register the chaincode example, within the build/distributions folder, execute the following script:

./Example/bin/Example

This runs a standalone process that registers the chaincode example with the local blockchain network. You should see terminal window output like this:

                $ ./Example/bin/Example
                Hello world! starting [Ljava.lang.String;@7ef20235
                Feb 22, 2017 10:05:08 AM example.Example main
                INFO: starting
                Feb 22, 2017 10:05:08 AM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
                INFO: Inside newPeerCLientConnection
                Feb 22, 2017 10:05:08 AM io.grpc.internal.TransportSet$1 call
                INFO: Created transport io.grpc.netty.NettyClientTransport@3dd7b80b(/127.0.0.1:7051) for /127.0.0.1:7051
                Feb 22, 2017 10:05:14 AM io.grpc.internal.TransportSet$TransportListener transportReady
                INFO: Transport io.grpc.netty.NettyClientTransport@3dd7b80b(/127.0.0.1:7051) for /127.0.0.1:7051 is ready

Take a look at the console for your local blockchain network, and you should see lines of output that look like this:

                .
                .
                vp0_1         | 16:05:14.048 [chaincode] HandleChaincodeStream -> DEBU 06d Current context deadline = 0001-01-01 00:00:00 +0000 UTC, ok = false
                vp0_1         | 16:05:14.065 [chaincode] processStream -> DEBU 06e []Received message REGISTER from shim
                vp0_1         | 16:05:14.065 [chaincode] HandleMessage -> DEBU 06f []Handling ChaincodeMessage of type: REGISTER in state created
                vp0_1         | 16:05:14.065 [chaincode] beforeRegisterEvent -> DEBU 070 Received REGISTER in state created
                vp0_1         | 16:05:14.065 [chaincode] registerHandler -> DEBU 071 registered handler complete for chaincode hello
                vp0_1         | 16:05:14.065 [chaincode] beforeRegisterEvent -> DEBU 072 Got REGISTER for chaincodeID = name:"hello" , sending back REGISTERED
                .
                .

Make a note of the chaincodeID name in the registration log output (hello for the Example; see line 8 in the preceding). You'll need that later for the JSON message when you deploy the Example chaincode through the fabric's REST interface.

The preceding output indicates that the Example chaincode is running and has been registered with the local blockchain validating peer network, and is ready to be deployed.

3

Deploy the example

The Hyperledger Fabric provides a REST web service interface that you use to interact with the fabric. The first interaction with the fabric is to deploy your chaincode. Make sure your local blockchain network is running, then start SoapUI, and click the REST button to create a new REST project. You should see a dialog box like Figure 3, where you enter the based URL used for all REST requests:

Figure 3. SoapUI New REST project dialog
SoapUI New REST project dialog
SoapUI New REST project dialog

Enter http://localhost:7050 as the URL, then click OK. Port 7050 is the default REST port used by the fabric, and since your blockchain network is running on your local computer, you will use localhost as the host name.

When SoapUI comes up, you can do a quick smoke test to make sure it can communicate with your local blockchain network. Expand the new REST resource you just created until you see Request 1, then open it in the Editor window. Use GET for the method, and under resource enter /chain. Make sure to click the JSON option on the output tab, then run the request (by clicking on the arrow icon). When you execute this request, it simply returns the current block hash in the output tab, located on the right-hand side of the editor window, as you can see in Figure 4:

Figure 4. Blockchain smoke test
Blockchain smoke test
Blockchain smoke test

If you see a JSON message that looks similar to the one in Figure 4 (the currentBlockHash value for your network will be different, of course), then you're ready to deploy the Example chaincode.

Right-click on the endpoint under REST Project 1 (http://localhost:7050) and choose New Resource; you should see a "New REST Resource" dialog box (see Figure 5) with a Resource Path field:

Figure 5. SoapUI New Resource dialog
SoapUI New Resource dialog
SoapUI New Resource dialog

Enter /chaincode as the resource path, then click OK, and you should see the new resource show up in your SoapUI Projects panel. Open up the request for this resource (by default it will be called Request 1), change the method to POST, and paste this JSON into the request area, located in the lower left corner of the request editor window:

                {
                "jsonrpc": "2.0",
                  "method": "deploy",
                  "params": {
                    "type": 1,
                    "chaincodeID":{
                        "name": "hello"
                    },
                    "CtorMsg": {
                        "args": [""]
                    }
                  },
                  "id": 1
                }

Three things to note:

  • Line 3: The method value must be deploy.
  • Lines 6-7: The chaincodeID.name in the JSON message must match the chaincodeID when you registered the Example chaincode in the previous section (hello for the Example chaincode).
  • Line 13: The id value is used to coordinate requests. You don't need to worry about it so much for this tutorial, but notice that it is always sent back on the response (see the next listing).

When you submit this request, the JSON output should look like this:

                {
                   "jsonrpc": "2.0",
                   "result":    {
                      "status": "OK",
                      "message": "hello"
                   },
                   "id": 1
                }

Figure 6 shows a screenshot of what this looks like in SoapUI. The JSON output message will appear in the output tab, which is located on the right-hand side of the request editor.

Figure 6. SoapUI Chaincode deploy request
SoapUI Chaincode                     deploy request
SoapUI Chaincode deploy request

The network log output in the terminal window should include lines that look like this:

                .
                .
                vp0_1         | 20:48:39.482 [rest] ProcessChaincode -> INFO 0c4 REST processing chaincode request...
                vp0_1         | 20:48:39.482 [rest] processChaincodeDeploy -> INFO 0c5 REST deploying chaincode...
                vp0_1         | 20:48:39.483 [devops] Deploy -> DEBU 0c6 Creating deployment transaction (hello)
                vp0_1         | 20:48:39.483 [devops] Deploy -> DEBU 0c7 Sending deploy transaction (hello) to validator
                vp0_1         | 20:48:39.483 [peer] sendTransactionsToLocalEngine -> DEBU 0c8 Marshalling transaction CHAINCODE_DEPLOY to send to local engine
                vp0_1         | 20:48:39.483 [peer] sendTransactionsToLocalEngine -> DEBU 0c9 Sending message CHAIN_TRANSACTION with timestamp seconds:1487796519 nanos:483661510  to local engine
                vp0_1         | 20:48:39.483 [consensus/noops] RecvMsg -> DEBU 0ca Handling Message of type: CHAIN_TRANSACTION 
                vp0_1         | 20:48:39.483 [consensus/noops] broadcastConsensusMsg -> DEBU 0cb Broadcasting CONSENSUS
                vp0_1         | 20:48:39.483 [peer] Broadcast -> DEBU 0cc Broadcast took 1.135s
                vp0_1         | 20:48:39.483 [consensus/noops] RecvMsg -> DEBU 0cd Sending to channel tx uuid: hello
                vp0_1         | 20:48:39.483 [rest] processChaincodeDeploy -> INFO 0ce Successfully deployed chainCode: hello
                vp0_1         | 20:48:39.484 [rest] ProcessChaincode -> INFO 0cf REST successfully deploy chaincode: {"jsonrpc":"2.0","result":{"status":"OK","message":"hello"},"id":1}
                .
                .

Lines 3-4 show the output indicating the network has received the deploy message and the fabric is deploying your chaincode. Lines 13-14 show that your chaincode has been deployed successfully.

Take note of output like this in the terminal window running your chaincode:

                $ ./build/distributions/Example/bin/Example
                Hello world! starting [Ljava.lang.String;@7ef20235
                Feb 22, 2017 2:44:43 PM example.Example main
                INFO: starting
                Feb 22, 2017 2:44:43 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
                INFO: Inside newPeerCLientConnection
                Feb 22, 2017 2:44:43 PM io.grpc.internal.TransportSet$1 call
                INFO: Created transport io.grpc.netty.NettyClientTransport@46adccd3(/127.0.0.1:7051) for /127.0.0.1:7051
                Feb 22, 2017 2:44:48 PM io.grpc.internal.TransportSet$TransportListener transportReady
                INFO: Transport io.grpc.netty.NettyClientTransport@46adccd3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
                Feb 22, 2017 2:48:40 PM example.Example run
                INFO: In run, function:
                Feb 22, 2017 2:48:40 PM example.Example run

I've included all of the output for context, and you should see lines like 11-13 when you send the deploy message to your blockchain network.

4

Invoke a transaction on the example

Finally, you will invoke the hello method and watch it show up in the log messages of the terminal window running your chaincode.

Under the chaincode resource in SoapUI, right-click on Method 1 and choose Clone Method. Call the method Invoke, and click OK. Open Request 1 under your new Invoke method and paste in this JSON request:

                {
                "jsonrpc": "2.0",
                  "method": "invoke",
                  "params": {
                    "type": 1,
                    "chaincodeID":{
                        "name": "hello"
                    },
                    "CtorMsg": {
                        "args": ["hello"]
                    }
                  },
                  "id": 2
                }

When you run the request, you should see this JSON response:

                {
                   "jsonrpc": "2.0",
                   "result":    {
                      "status": "OK",
                      "message": "1c1811d0-a958-4c58-ab1d-e1df550c18a3"
                   },
                   "id": 2
                }

Figure 7 shows a screenshot of what this looks like in SoapUI.

Figure 7. SoapUI Chaincode invoke request
SoapUI Chaincode                     invoke request
SoapUI Chaincode invoke request

The network log output should include lines that look like this:

                .
                .
                vp0_1         | 21:44:35.143 [rest] ProcessChaincode -> INFO 555 REST processing chaincode request...
                vp0_1         | 21:44:35.143 [rest] processChaincodeInvokeOrQuery -> INFO 556 REST invoke chaincode...
                vp0_1         | 21:44:35.143 [devops] invokeOrQuery -> INFO 557 Transaction ID: 1c1811d0-a958-4c58-ab1d-e1df550c18a3
                vp0_1         | 21:44:35.143 [devops] createExecTx -> DEBU 558 Creating invocation transaction (1c1811d0-a958-4c58-ab1d-e1df550c18a3)
                vp0_1         | 21:44:35.143 [devops] invokeOrQuery -> DEBU 559 Sending invocation transaction (1c1811d0-a958-4c58-ab1d-e1df550c18a3) to validator
                vp0_1         | 21:44:35.143 [peer] sendTransactionsToLocalEngine -> DEBU 55a Marshalling transaction CHAINCODE_INVOKE to send to local engine
                vp0_1         | 21:44:35.143 [peer] sendTransactionsToLocalEngine -> DEBU 55b Sending message CHAIN_TRANSACTION with timestamp seconds:1487799875 nanos:143438691  to local engine
                vp0_1         | 21:44:35.143 [consensus/noops] RecvMsg -> DEBU 55c Handling Message of type: CHAIN_TRANSACTION 
                vp0_1         | 21:44:35.143 [consensus/noops] broadcastConsensusMsg -> DEBU 55d Broadcasting CONSENSUS
                vp0_1         | 21:44:35.143 [peer] Broadcast -> DEBU 55e Broadcast took 1.249s
                vp0_1         | 21:44:35.143 [consensus/noops] RecvMsg -> DEBU 55f Sending to channel tx uuid: 1c1811d0-a958-4c58-ab1d-e1df550c18a3
                vp0_1         | 21:44:35.143 [rest] processChaincodeInvokeOrQuery -> INFO 560 Successfully submitted invoke transaction with txid (1c1811d0-a958-4c58-ab1d-e1df550c18a3)
                vp0_1         | 21:44:35.143 [rest] ProcessChaincode -> INFO 561 REST successfully submitted invoke transaction: {"jsonrpc":"2.0","result":{"status":"OK","message":"1c1811d0-a958-4c58-ab1d-e1df550c18a3"},"id":2}
                .
                .

And the chaincode log output like this:

                $ ./build/distributions/Example/bin/Example
                Hello world! starting [Ljava.lang.String;@7ef20235
                Feb 22, 2017 3:26:57 PM example.Example main
                INFO: starting
                Feb 22, 2017 3:26:57 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
                INFO: Inside newPeerCLientConnection
                Feb 22, 2017 3:26:57 PM io.grpc.internal.TransportSet$1 call
                INFO: Created transport io.grpc.netty.NettyClientTransport@765e4953(/127.0.0.1:7051) for /127.0.0.1:7051
                Feb 22, 2017 3:27:02 PM io.grpc.internal.TransportSet$TransportListener transportReady
                INFO: Transport io.grpc.netty.NettyClientTransport@765e4953(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
                Feb 22, 2017 3:27:24 PM example.Example run
                INFO: In run, function:
                Feb 22, 2017 3:27:24 PM example.Example run
                SEVERE: No matching case for function:
                Feb 22, 2017 3:30:55 PM example.Example run
                INFO: In run, function:hello
                hello invoked

Once again, I've shown all the chaincode output. You can see where the hello function was invoked (line 16).

Now you've seen how to build, deploy, and run Java chaincode on your local blockchain network. In the next section, you'll write a chaincode program (almost) from scratch using the Eclipse IDE, build the chaincode program using Gradle, and exercise it using SoapUI.

Write your first Java chaincode program

In the previous section, you got familiar with how to build, run, deploy, and invoke chaincode, but you haven't yet written any Java code.

In this section, you'll use the Eclipse IDE, a plugin for Gradle that works with Eclipse, and a skeleton Java chaincode project called ChaincodeTutorial to write your first Java chaincode program. You'll get the skeleton code from a GitHub repo I created for this tutorial, import that code into Eclipse, add code to make the chaincode smart contract function according to the requirements, and build that code using Gradle from within your Eclipse IDE.

Here are the steps you'll follow:

  1. Install the Gradle Buildship plugin for Eclipse.
  2. Clone the ChaincodeTutorial project from GitHub.
  3. Import the project into Eclipse.
  4. Explore the chaincode skeleton project.
  5. Write the Java chaincode.
  6. Build the Java chaincode.

When you've completed this section, your chaincode will be ready to run on your local blockchain network.

1

Install the Gradle Buildship plugin for Eclipse

You can use any IDE you like, but the instructions in this tutorial are for Eclipse. Note: The Buildship Gradle plugin helps integrate Gradle with Eclipse, but you will still need to have installed Gradle on your computer.

If you've been following along with the tutorial, you should already have Gradle installed on your computer; if it's not installed, do that now. Refer to the "Install the build software" section to see how to install Gradle on your computer.

To install the Buildship Gradle plugin for Eclipse, which helps your Gradle installation work with Eclipse, within Eclipse, go to Help > Eclipse Marketplace... In the Eclipse Marketplace dialog, enter buildship in the Find text field and click the Go button. You should see something like Figure 8, showing the Buildship Gradle Integration 2.0 plugin as the first result of the search:

Figure 8. Eclipse Marketplace: Gradle Buildship plugin
Eclipse Marketplace: Gradle Buildship plugin
Eclipse Marketplace: Gradle Buildship plugin

Under Buildship Gradle Integration, click the Install button and follow the prompts. When you click Finish, the Buildship Gradle plugin for Eclipse will be installed, and you'll be asked to restart Eclipse.

When Eclipse reopens, Gradle should be fully integrated with your Eclipse IDE. You are now ready to clone the ChaincodeTutorial repository from GitHub.

2

Clone the ChaincodeTutorial project from GitHub

Now that you have your Eclipse IDE configured to work with Gradle, you will clone the ChaincodeTutorial code from GitHub and import the code into Eclipse. Open a command prompt or terminal window, navigate to your $GOPATH, and execute this command:

git clone https://github.com/makotogo/ChaincodeTutorial.git

Your command output should look something like this:

                $ export GOPATH=/Users/sperry/home/mychaincode
                $ cd $GOPATH
                $ git clone https://github.com/makotogo/ChaincodeTutorial.git
                Cloning into 'ChaincodeTutorial'...
                remote: Counting objects: 133, done.
                remote: Compressing objects: 100% (90/90), done.
                remote: Total 133 (delta 16), reused 118 (delta 1), pack-reused 0
                Receiving objects: 100% (133/133), 9.39 MiB | 1.95 MiB/s, done.
                Resolving deltas: 100% (16/16), done.
                $ cd ChaincodeTutorial
                $ pwd
                /Users/sperry/home/mychaincode/ChaincodeTutorial

This command clones the Blockchain ChaincodeTutorial repo from GitHub to your $GOPATH. It consists of a skeleton Java chaincode project you can build, run, and experiment with in your local blockchain network.

But before you can do any of that, you need to import the code into Eclipse.

3

Import the project into Eclipse

In Eclipse, go to File > Import... > Gradle > Existing Gradle project. A wizard dialog box should open (see Figure 9).

Figure 9. Eclipse Import Wizard: Gradle Project
Eclipse Import Wizard: Gradle                     Project
Eclipse Import Wizard: Gradle Project

Click Next. On the dialog box that comes up next in the wizard (see Figure 10), browse to $GOPATH/ChaincodeTutorial, and click Finish to import the project.

Figure 10. Eclipse Import Wizard: Gradle Project (Project root directory)
Eclipse Import Wizard: Gradle                     Project (Project root directory)
Eclipse Import Wizard: Gradle Project (Project root directory)

When the project has finished importing, make sure to select the Java Perspective, and the ChaincodeTutorial project you just imported will show up in the Project Explorer view.

Now that you have the code imported into your Eclipse workspace, you are ready to write your chaincode.

4

Explore the chaincode skeleton project

In this section you'll explore the chaincode project so you understand how it is supposed to function before you write any Java code.

As developers, we love to write code, so I don't want to deprive you of the opportunity to write Java code. However, the project setup can be complex, and I don't want that to get in the way of the main point of this tutorial. To that end, I've provided most of the code you will need.

Before you jump in, let's take a quick look at the base class, called AbstractChaincode, which is located in the com.makotojava.learn.blockchain.chaincode package, and shown in Listing 1.

Listing 1. The AbstractChaincode class
                package com.makotojava.learn.blockchain.chaincode;
                
                import java.util.Arrays;
                
                import org.apache.commons.logging.Log;
                import org.apache.commons.logging.LogFactory;
                import org.hyperledger.java.shim.ChaincodeBase;
                import org.hyperledger.java.shim.ChaincodeStub;
                
                public abstract class AbstractChaincode extends ChaincodeBase {
                
                  private static final Log log = LogFactory.getLog(AbstractChaincode.class);
                
                  public static final String FUNCTION_INIT = "init";
                  public static final String FUNCTION_QUERY = "query";
                
                  protected abstract String handleInit(ChaincodeStub stub, String[] args);
                  protected abstract String handleQuery(ChaincodeStub stub, String[] args);
                  protected abstract String handleOther(ChaincodeStub stub, String function, String[] args);
                
                  @Override
                  public String run(ChaincodeStub stub, String function, String[] args) {
                    String ret;
                    log.info("Greetings from run(): function -> " + function + " | args -> " + Arrays.toString(args));
                    switch (function) {
                    case FUNCTION_INIT:
                      ret = handleInit(stub, args);
                      break;
                    case FUNCTION_QUERY:
                      ret = handleQuery(stub, args);
                    default:
                      ret = handleOther(stub, function, args);
                      break;
                    }
                    return ret;
                  }
                
                  @Override
                  public String query(ChaincodeStub stub, String function, String[] args) {
                    return handleQuery(stub, args);
                  }
                
                }

The first thing I want to point out is that AbstractChaincode is a subclass of ChaincodeBase, which is from the fabric shim client (lines 7, 10).

Lines 17-19 show the methods you need to implement in the ChaincodeLog class (which is a subclass of AbstractChaincode) to handle the initialization, ledger query, and log functions, respectively.

Lines 22-36 show the run() method of the ChaincodeBase class (from the chaincode shim client), where we figure out what function has been invoked and to which handler the call should be delegated. The class is extensible in that any other functions than init and query (such as the log function) are handled by handleOther(), which you must also implement.

Now, open the ChaincodeLog class in the com.makotojava.learn.blockchain.chaincode package.

I've provided only a skeleton for you to flesh out — that is, I've provided just enough code so that it compiles. You'll have to write the rest of the code. You should run the JUnit tests and see that they fail (because you haven't written the implementation yet), and why. In other words, you can use the JUnit tests as a guide for properly implementing the code.

Now, if this feels a little over your head, don't worry; I've provided the solution, which is located in com.makotojava.learn.blockchain.chaincode.solution, in case you get stuck (or if you just want a reference to guide you through the implementation).

5

Write the Java chaincode

First, a little background on what you need to know in order to implement the chaincode methods in ChaincodeLog. The ChaincodeStub class is how your Java chaincode communicates with the Hyperledger Fabric framework, and recall that the ledger is at the core of the transparency aspect of blockchain technology. What makes a smart contract (accountability) work is the state of the ledger, and your chaincode accesses the ledger's state through the ChaincodeStub. By accessing the ledger state, you're able to implement a smart contract (a.k.a., chaincode).

There are a number of methods on ChaincodeStub that allow you to store, retrieve, and remove items from the ledger's current state, but I'll limit our discussion in this tutorial to two methods, which store and retrieve the ledger state:

putState(String key, String value)— Stores the specified state value in the ledger, mapped according to the specified key.

getState()— Gets the state value associated with the specified key and returns it as a String

When writing the code for this tutorial, you will use the putState() and getState() functions whenever you need to store or retrieve state values from the ledger, respectively. The ChaincodeLog class only stores and retrieves values from the ledger to implement its smart contract, so this is all you need to know to implement the methods. More complicated chaincode would make use of some of the other methods in ChaincodeStub (but those are also beyond the scope of this tutorial).

I'm a big fan of test-driven development (TDD), so in TDD fashion, I've written the unit tests first. Go ahead and run them and watch them fail. After that, you'll write code that follows the specifications until the unit tests pass. The job of the unit tests is to ensure the expected behavior, and by studying the unit tests, you should have enough information to implement the methods.

However, I have also written javadoc comments at the top of each method that might help (in case you're new to TDD or JUnit). Between the code in the JUnit tests and the javadoc comments in the skeleton ChaincodeLog, you should have everything you need to implement the chaincode after you complete this section of the tutorial.

From the Project Explorer view (in the Java perspective) navigate to the ChaincodeLogTest class, right-click on it and choose Run As > Gradle Test. When it runs, you should see something like Figure 11, showing the tree of all Gradle tasks that ran. Tasks that completed successfully are indicated with check marks next to them.

Figure 11. Eclipse: Gradle Executions view
Eclipse: Gradle Executions view
Eclipse: Gradle Executions view

The exclamation icons in the Gradle Executions tab indicate the Gradle tasks corresponding to the unit tests that failed (there are four and they all failed, just as we expected).

Because of the way I've written the JUnit test cases, each test method corresponds to a method in ChaincodeLog that you'll have to correctly implement as part of this tutorial.

Implement getChaincodeID()

First, you need to implement getChaincodeID(). Its contract is to return the unique identifier for your chaincode. I've defined a constant called CHAINCODE_ID at the top of the ChaincodeLog class that you should use. Feel free to change its value, but if you change the chaincode id returned by getChaincodeID(), make sure it is unique within your network, and don't forget to change the ChaincodeID.name attribute of your JSON messages as well.

                  /**
                   * Returns the unique chaincode ID for this chaincode program.
                   */
                  @Override
                  public String getChaincodeID() {
                    return null;// ADD YOUR CODE HERE
                  }

Exercise: Complete the getChaincodeID() method. If you need a reference, look in the com.makotojava.learn.blockchain.chaincode.solution package.

Implement handleInit()

Next, implement the handleInit() method. Its contract is to handle initializing your chaincode program, which in this case means that it will add a message (specified by the caller) to the ledger and return that message to the caller if the call succeeds.

                  /**
                   * Handles initializing this chaincode program.
                   *
                   * Caller expects this method to:
                   *
                   * 1. Use args[0] as the key for logging.
                   * 2. Use args[1] as the log message.
                   * 3. Return the logged message.
                   */
                  @Override
                  protected String handleInit(ChaincodeStub stub, String[] args) {
                    return null;// ADD YOUR CODE HERE
                  }

Exercise: Complete the handieInit() method. If you need a reference, look in the com.makotojava.learn.blockchain.chaincode.solution package.

Implement handleQuery()

Next up is the handleQuery() method. Its contract is to query the ledger, which it does by taking the specified key(s), querying the ledger for the value(s) that matches the key(s), and returning the value(s) to the caller. If multiple keys are specified, the values that are returned should be separated by commas.

                  /**
                   * Handles querying the ledger.
                   *
                   * Caller expects this method to:
                   * 
                   * 1. Use args[0] as the key for ledger query.
                   * 2. Return the ledger value matching the specified key
                   *    (which should be the message that was logged using that key).
                   */
                  @Override
                  protected String handleQuery(ChaincodeStub stub, String[] args) {
                    return null;// ADD YOUR CODE HERE
                  }

Be sure to write code to output the results of the query call, so you can see the results in the console output (take a peek at the solution if you want to see how I did it).

Exercise: Complete the handleQuery() method. If you need a reference, look in the com.makotojava.learn.blockchain.chaincode.solution package.

Implement handleOther()

Finally, you need to implement the handleOther() method, whose contract is to handle other messages (which is pretty wide open, but that's why it's extensible). This is where you will implement the log function, whose contract is to add a message specified by the caller to the ledger, and return that message to the caller if the call was successful. This looks very similar to what happens in the init function, so perhaps you could leverage that in your implementation.

                  /**
                   * Handles other methods applied to the ledger.
                   * Currently, that functionality is limited to these functions:
                   * - log
                   *
                   * Caller expects this method to:
                   * Use args[0] as the key for logging.
                   * Use args[1] as the log message.
                   * Return the logged message.
                   */
                  @Override
                  protected String handleOther(ChaincodeStub stub, String function, String[] args) {
                    // TODO Auto-generated method stub
                    return null;// ADD YOUR CODE HERE
                  }

Exercise: Complete the handleOther() method. If you need a reference, look in the com.makotojava.learn.blockchain.chaincode.solution package.

If the code you wrote for each of the preceding exercises meets the requirements as I've laid them out in this section (and in the code comments), then your JUnit tests should all pass, and your chaincode should work fine when it is deployed and running in your local blockchain network.

Remember, I've provided a solution in case you get stuck (but you owe it to yourself to try to implement the methods on your own before peeking at the solution).

6

Build the Java chaincode

Now that you've written your Java chaincode and all your JUnit tests pass, it's time for you to build your chaincode using Eclipse and the Gradle Buildship plugin for Eclipse. Pull up the Gradle Tasks view by going to Window > Show View > Other... then search for gradle, select Gradle Tasks, and click OK. (See Figure 12.)

Figure 12. Eclipse: Show View: Gradle Tasks view
Eclipse: Show View: Gradle Tasks view
Eclipse: Show View: Gradle Tasks view

When the Gradle Tasks view opens, expand the ChaincodeTutorial > build node, and select build and clean. (See Figure 13.)

Figure 13. Eclipse: Gradle Tasks view
Eclipse: Gradle Tasks view
Eclipse: Gradle Tasks view

Right-click on build and clean, then choose Run Gradle Tasks (Gradle will figure out the correct order to run these). Your Gradle Executions view should show a clean build, as shown in Figure 14, where you have only check marks next to each item.

Figure 14. Eclipse: Gradle Executions view: clean build
Eclipse: Gradle Executions                     view: clean build
Eclipse: Gradle Executions view: clean build

When the build finishes, you should have a directory immediately subordinate to your $GOPATH/ChaincodeTutorial directory (where you cloned the code from GitHub earlier) called build/distributions that contains your chaincode (this should look familiar, as you did this earlier in the tutorial for the hello example).

Now that you have built your Java chaincode, you are ready to deploy, run, and invoke transactions on it in your local blockchain network.

Deploy and run your Java chaincode

In this section, you will start and register your chaincode, deploy it, and invoke transactions on it via the Hyperledger Fabric REST interface, as you did earlier in the tutorial with the hello example. Make sure your local blockchain is running (see the section, "Start the blockchain network" for a refresher on this).

Here are the steps you will follow:

  1. Register your Java chaincode.
  2. Deploy your Java chaincode.
  3. Invoke transactions on your Java chaincode.
1

Register your Java chaincode

You will need to extract the build/distributions/ChaincodeTutorial.zip file and run the chaincode script, exactly as you did earlier in this tutorial when running the hello example (see the section, "Register the example").

When you run the ChaincodeTutorial script, the output should look something like this:

                $ ./ChaincodeTutorial/bin/ChaincodeTutorial
                Feb 28, 2017 4:18:16 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
                INFO: Inside newPeerCLientConnection
                Feb 28, 2017 4:18:16 PM io.grpc.internal.TransportSet$1 call
                INFO: Created transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051
                Feb 28, 2017 4:18:21 PM io.grpc.internal.TransportSet$TransportListener transportReady
                INFO: Transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready

Now your Java chaincode is registered with your local blockchain network, and you're ready to deploy and test your chaincode.

2

Deploy your Java chaincode

As you did with the hello example chaincode, you will use the fabric's REST interface to deploy and invoke transactions on your Java chaincode.

Open SoapUI. If you are comfortable doing so, you can create a new REST project and all of its requests yourself, or you can import the SoapUI REST project that I have included in the GitHub project you cloned earlier. The SoapUI project is located in the $GOPATH/ChaincodeTutorial directory.

To deploy your chaincode, navigate to the ChaincodeLog Deploy request, as shown in Figure 15, and submit the request.

Figure 15. SoapUI: ChaincodeLog Deploy request
SoapUI: ChaincodeLog Deploy                     request
SoapUI: ChaincodeLog Deploy request

If you are not using the SoapUI project from GitHub (or are using a different HTTP client), the JSON request you should submit looks like this:

                {
                "jsonrpc": "2.0",
                  "method": "deploy",
                  "params": {
                    "type": 4,
                    "chaincodeID":{
                        "name": "ChaincodeLogSmartContract"
                    },
                    "ctorMsg": {
                        "args": ["init", "KEY-1", "Chaincode Initialized"]
                    }
                  },
                  "id": 1
                }

Submit the request. If it succeeds you should get a JSON response like this one:

                {
                   "jsonrpc": "2.0",
                   "result":    {
                      "status": "OK",
                      "message": "ChaincodeLogSmartContract"
                   },
                   "id": 1
                }

Now your chaincode is deployed and ready to run.

3

Invoke transactions on your Java chaincode

Now that your Java chaincode is deployed and initialized, you can invoke transactions on it. In this section, you will invoke the log and query functions as transactions.

To invoke the log function, open the ChaincodeLog Log request and submit the request. (See Figure 16.)

Figure 16. SoapUI: ChaincodeLog log request
SoapUI: ChaincodeLog log                     request
SoapUI: ChaincodeLog log request

If you're not using the SoapUI project from GitHub (or are using a different HTTP client), the JSON request you should submit looks like this:

                {
                "jsonrpc": "2.0",
                  "method": "invoke",
                  "params": {
                    "type": 1,
                    "chaincodeID":{
                        "name": "ChaincodeLogSmartContract"
                    },
                    "CtorMsg": {
                        "args": ["log", "KEY-2", "This is a log message."]
                    }
                  },
                  "id": 2
                }

If the request succeeds, you should get a JSON response like this one:

                {
                   "jsonrpc": "2.0",
                   "result":    {
                      "status": "OK",
                      "message": "a6f7a4fc-2980-4d95-9ec2-114dd9d0e4a5"
                   },
                   "id": 2
                }

To invoke the query function, open the ChaincodeLog Query request and submit the request. (See Figure 17.)

Figure 17. SoapUI: ChaincodeLog Query request
SoapUI: ChaincodeLog Query request
SoapUI: ChaincodeLog Query request

If you are not using the SoapUI project from GitHub (or are using a different HTTP client), the JSON request you should submit looks like this:

                {
                "jsonrpc": "2.0",
                  "method": "invoke",
                  "params": {
                    "type": 1,
                    "chaincodeID":{
                        "name": "ChaincodeLogSmartContract"
                    },
                    "ctorMsg": {
                        "args": ["query", "KEY-1", "KEY-2"]
                    }
                  },
                  "id": 3
                }

If the request succeeds, you should get a JSON response like this one:

                {
                   "jsonrpc": "2.0",
                   "result":    {
                      "status": "OK",
                      "message": "84cbe0e2-a83e-4edf-9ce9-71ae7289d390"
                   },
                   "id": 3
                }

The terminal window output of the solution code looks like this:

                $ ./ChaincodeTutorial/bin/ChaincodeTutorial
                Feb 28, 2017 4:18:16 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection
                INFO: Inside newPeerCLientConnection
                Feb 28, 2017 4:18:16 PM io.grpc.internal.TransportSet$1 call
                INFO: Created transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051
                Feb 28, 2017 4:18:21 PM io.grpc.internal.TransportSet$TransportListener transportReady
                INFO: Transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
                Feb 28, 2017 4:34:52 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run
                INFO: Greetings from run(): function -> init | args -> [KEY-1, Chaincode Initialized]
                Feb 28, 2017 4:34:52 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleLog
                INFO: *** Storing log message (K,V) -> (ChaincodeLogSmartContract-CLSC-KEY-1,Chaincode Initialized) ***
                Feb 28, 2017 4:50:27 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run
                INFO: Greetings from run(): function -> log | args -> [KEY-2, This is a log message.]
                Feb 28, 2017 4:50:27 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleLog
                INFO: *** Storing log message (K,V) -> (ChaincodeLogSmartContract-CLSC-KEY-2,This is a log message.) ***
                Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run
                INFO: Greetings from run(): function -> query | args -> [KEY-1, KEY-2]
                Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleQuery
                INFO: *** Query: For key 'ChaincodeLogSmartContract-CLSC-KEY-1, value is 'Chaincode Initialized' ***
                Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleQuery
                INFO: *** Query: For key 'ChaincodeLogSmartContract-CLSC-KEY-2, value is 'This is a log message.' ***

Congratulations! You've just taken the first step into your future.

I encourage you to play around with the ChaincodeTutorial project, add methods to it, change the implementations, and so forth. Get comfortable with writing chaincode. Good luck, and have fun!

Conclusion

This tutorial gave you a brief overview of blockchain technology and of the smart contract, which is implemented as a chaincode program, and the current technology landscape with respect to blockchain.

We went through the steps to set up your Java chaincode development environment, including the software you need to install, how to define and run your local blockchain network, and how to deploy and invoke transactions against one of the example Java chaincode programs from the Hyperledger Fabric project in GitHub.

You learned how to use Eclipse, JUnit, and Gradle to write and build your first Java chaincode program, and then deploy and invoke transactions against your Java chaincode program.

You've taken a hands-on look at blockchain technology and smart contracts, and are positioned perfectly to write more complex Java chaincode as blockchain technology matures and proliferates in the marketplace.

So where you do you go from here?

Next steps

Here are a few suggestions to help you build on what you've learned so far:


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java development, Blockchain
ArticleID=1043805
ArticleTitle=Blockchain chaincode for Java developers
publish-date=03152017