[CouchDB] Hyperledger Fabric Account-based Wallet Java Chaincode

CouchDB Version — Account-based Wallet Model in A Transaction System

Sam LAM @ OriginBit
Coinmonks
Published in
8 min readMar 21, 2019

--

Hyperledger Fabric Image

This is a tutorial for Hyperledger Fabric Java Chaincode with CouchDB.

Basically, this tutorial is the CouchDB version of my previous story — Hyperledger Fabric Account-based Wallet Java Chaincode, but with some new functions to demonstrate what the CouchDB could provide us — Rich Query, that enables us to query our blockchain data in a more flexible way, such as a query of “all wallets with balance greater than $10”. While in LevelDB, data is simply stored as a key-value pair.

Note that, in general, LevelDB has a better performance than CouchDB’s, while CouchDB could provide us Rich Query. The option depends on the use case.

Before We Start

We will use Hyperledger Fabric “Build Your First Network (BYFN)” as our testing environment (v1.4 network)

In case you don’t know how to start a “BYFN” network, I will also provide the steps, no worry. But If you want to learn how “BYFN” works, you could refer to:

(1) Hyperledger Fabric official “BYFN” tutorial

(2) My previous story about “BYFN”

What Account-based Wallet Model Is Basically

Account-based wallet model is one of the implementations of the transaction system, in which, generally speaking, there are wallets and each wallet contains some values or tokens that could be used to transfer. Of course, there are lots of variations on the details of the implementations, such as the token exchange and multi-tokens features.

Features

In the Java Chaincode, we will implement:

  1. User wallet creation
  2. User wallet query with a walletId
  3. Wallet token transfer (i.e. to send money or tokens to from one wallet another wallet)
  4. User wallet query with a condition that the token amount needs to be greater than a certain value (new feature in this CouchDB version tutorial!)

The IDE — Tool for Development of Java Chaincode

We use IntelliJ IDEA Community. Also, you need to have JDK. Please install them.

Of course, if you have your own Java IDE, you could also use that. But in this tutorial, I use IntelliJ.

Step 1 — Preparation for Development

Let’s open IntelliJ.

Create New Project in IntelliJ:

Choose Gradle on the left, then Next:

Type your GroupId and ArtifactId. In my case, I use “java_account_model_cc” for both. Then Next:

Then, just next. Now, you should configure your own project location. In my case, I use “~/Desktop/java_account_model_cc”. Click Finish.

1.1 settings.gradle

In the project files on the left, you should have “settings.gradle”. Let’s double click to open it:

Project files on the left panel

Type the following:

settings.gradle

1.2 build.gradle

In the project files panel on the left, you should have “build.gradle”. Let’s double click to open it.

Then, type the following:

build.gradle

*If there is a “Gradle project needs to be imported” popup on the bottom right in your IntelliJ, let’s choose “Import Changes”.

1.3 The Chaincode File

In the project files panel on the left, under src > main > java, right click on it and choose New > Java Class:

Type “org.hyperledger.fabric.chaincode.AccountBasedChaincode” for the Name field:

org.hyperledger.fabric.chaincode.AccountBasedChaincode

Then, you should have the following:

AccountBasedChaincode(.java) above is the place we write Chaincode in Java.

Step 2 — Analysis of the Requirement

Before we start coding, let’s organize what we need to code.

As said in the “Features” section, in the Java Chaincode, we will implement:

  1. User wallet creation
  2. User wallet query with a walletId
  3. Wallet token transfer (i.e. to send money to from one wallet another wallet)
  4. User wallet query with a condition that the token amount needs to be greater than a certain value

From this simple requirement above, we need to have the following classes:

  1. Wallet Class
  2. The Chaincode class — holding the Chaincode

And our Chaincode should provide these functions:

  1. Create a wallet
  2. Transfer tokens from one wallet to another
  3. Get (query) a wallet with a walletId
  4. Get (query) some wallets with a condition that the token amount needs to be greater than a certain value
  5. Init function — called when the Chaincode is instantiated
  6. Invoke function — called when a user wants to call the function (1), (2), (3), or (4)

The Init function must be implemented in Chaincode and will be called automatically whenever we instantiate or upgrade the Chaincode. Usually, it is used to initialize some data in the Blockchain.

The Invoke function is used to receive all user function calls, then based on the call, it invokes (calls) the corresponding function — (1), (2), (3), or (4). It is like a router — routing incoming requests to a different path.

Step 3 — The Wallet Class

Now, we create and code the Wallet class.

Create a new package under “org.hyperledger.fabric.chaincode”:

Call the package Models, then OK:

Package “Models”

Now you should have the following:

Under the Models package, create a new Java class and name it Wallet. (I don’t show detailed steps this time, let’s try yourself)

Creating Wallet class under Models package

Now we code for the Wallet class, let’s type:

Wallet.java

The wallet has a wallet id to identify a certain wallet and a token amount to specify how many tokens the wallet owns.

Note that in the production case, the Wallet class should be (far) more complicated. For example, you probably use “BigDecimal” data type instead of “Double” for tokenAmount. Also, in our case, we support only one token type (i.e. only one currency) in the whole transaction system.

Step 4 — The Chaincode Class

Note that there are two new functions in this tutorial, compared to the previous one — query() and getWalletsWithTokenAmountGreaterThan(). I have put some comments above them.

Note that in the production case, the codes should be different from mine. These codes are in demo or tutorial purpose mainly.

Step 5 — Running the Chaincode in BYFN

5.1 Install Prerequisites

We use Hyperledger Fabric v1.4 in this tutorial.

First of all, you could install prerequisites by following the official instructions:

  1. Install prerequisites
  2. Install samples, programs, and docker images from Hyperledger Fabric

5.2 Chaincode Preparation

Then, let’s switch to this directory (*supposed that you finish the prerequisite part, you should have all needed files and directories):

cd fabric-samples/chaincode/chaincode_example02/
mv java java_01
mkdir java

Now, copy the following highlighted files in your project directory to ”fabric-samples/chaincode/chaincode_example02/java/”:

Copy the highlighted files to ”fabric-samples/chaincode/chaincode_example02/java/”

5.3 Bring Up the Network

cd ../../first-network
./byfn.sh up -l java -s couchdb

Note that this time, there is a “-s couchdb” to enable CouchDB.

After running this script, you might need to wait for a moment…

*** If you see the following error (instead of other errors), that’s OKAY, just proceed to the next steps ***

Allowable error in our tutorial

Also, remember to start Docker, before you run the command above.

*In case you make something wrongly, you can run the following commands to turn down the network, and bring up again:

./byfn.sh down
./byfn.sh up -l java -s couchdb

Now, we test whether our Chaincode works.

5.4 Access the Cli

There is a cli Docker container created automatically, it is a command line interface to control the nodes.

Let’s get access to the cli:

docker exec -it cli bash

Then, set up environment variables used by some programs:

export CHANNEL_NAME=mychannel
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

You could just copy all of them, then paste to your terminal and press “enter”.

These environment variables are used to let some Hyperledger Fabric programs know that we need to use peer0.org1.example.com:7051 to invoke Chaincode functions.

Now, we create two wallets with wallet IDs — “tom” and “sam”:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["createWallet","tom","100"]}'peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["createWallet","sam","200"]}'

Note that Tom has $100 and Sam has $200.

Update: Note that we have two --peerAddresses in order to send to 2 Peers to endorse the transaction, since the default endorsement policy in Build Your First Network (BYFN) is an AND policy, which requires both organizations, Org1 and Org2, to sign each transaction. For more explainations, please refer to here.

You should see something like this in the terminal after running each command above:

Success message from Chaincode

Now, we get two wallets created above to verify whether they are existing in the Blockchain:

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["getWallet","tom"]}'peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["getWallet","sam"]}'

You should see something like this in the terminal after running each command above:

Above, we can see that the two wallets created previously can be queried. Also, Tom has 100 tokens and Sam has 200 tokens.

Next, we make a transfer transaction — let’s transfer 50 tokens from “tom” wallet to “sam” wallet:

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["transfer","tom","sam","50"]}'

Finally, let’s verify two wallets again:

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["getWallet","tom"]}'peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["getWallet","sam"]}'

Can you have the following result?

Note that now Tom’s wallet remains 50 tokens and Sam’s wallet has 250 tokens, the transaction is done and written into the Blockchain ledger.

Test the New Function for CouchDB

Now we try our new functions for this CouchDB version tutorial.

Remember that:

  • Tom now has $50
  • Sam now has $250

We will try to query all wallets with a token amount:

  1. > $40
  2. > 200

In (1), we should be able to obtain both Tom’s and Sam’s wallets.

In (2), we should be able to obtain Sam’s wallet only.

Now, let’s query:

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["getWalletsWithTokenAmountGreaterThan","40"]}'peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["getWalletsWithTokenAmountGreaterThan","200"]}'

Can you have the following result?

Step 6 — Cleaning Up

exit
./byfn.sh down

Then, delete directory “fabric-samples/chaincode/chaincode_example02/java” and rename directory ”java_01” back to ”java”.

Thanks! If you like my stories, please follow me for new updates!

--

--

Sam LAM @ OriginBit
Coinmonks

OriginBit Founder | HSUHK Lecturer | Gov Advisory Committee Member(SCSDITE) | GDG Organizer | MBuddhStud(HKU) | BEng(HKUST) | MCSE | MCP | CCNP | CEH