Skip to Content
Author's profile photo Murali Shanmugham

Creating blockchain based applications in SAP Cloud Platform

In this blog I would like to share my experience building an application which consumes some of the Leonardo services. This was something I have been working on for an internal training. This consumer app provides an option for the end user to take a picture of a product  and view the details of the product along with the product review. Below are the high level tasks which the app would perform.

  • Process the image by leveraging the Machine Learning services of SAP Cloud Platform (SAP CP) to identify the product
  • Lookup the product details which have been replicated to the HANA database
  • Retrieve product reviews which are stored in the blockchain service

Below is the solution diagram which shows the SAP CP components involved.

The focus of this blog is only on the Blockchain service. If you would like to know how to use the Machine Learning services or use the new HANA service on Cloud Foundry, you could follow the below blogs.

 

Below is the final output of the application which I built. After uploading the image, the app will use the standard pre-trained ML image classification service to identify the product as an Apple iPod and then retrieve the Product master details from HANA service and its reviews form Blockchain service.

Setup Blockchain service

In order to being working on the Hyperledger blockchain service, you would need entitlements in your Global SAP CP account. In the below screenshot, I have assigned all the relevant entitlements to my Cloud Foundry subaccount.

Configuring Hyperledger blockchain service

Once the entitlements have been assigned to your subaccount, you should be able to see the Hyperledger Fabric service in the service marketplace.

Click on the Hyperledger Fabric service and in the “Instances” menu create a new instance.

Select the plan as “dev” and accept the defaults.

In the last screen, provide a name for your instance. In my example, I have given the name “MyHyperLedger”.

Once your instance is created, open the dashboard. When prompted for login credentials, provide your SAP CP credentials (use email ID) to access the dashboard.

In the Dashboard, you should be able to see an order node and set of peers which are in running state. For this scenario, I am using Channels. Channels are like a private subnet of communication between specific members in the network and the transactions are only visible to those.

Navigate to the channels menu and create a channel specifically to maintain product reviews.

Once you have created a channel, create a service instance by clicking on the icon in the right hand corner

In the popup, you can provide a service instance name or accept the defaults.

Access the Service Instance dashboard by clicking on the icon shown below.

In this dashboard, you can explore all the transactions which have been carried out in this channel. In order interact with Hyperledger service, we would need keys. In the Overview menu, locate Service Keys section and type in “authkey” and click on “create key” button. This should give you a Client ID and Client Secret. Make a note of these. You will also need the URL when invoking the APIs later.

 

Uploading a chaincode program to the channel

Chaincode programs (referred to as smart contracts) embed the business logic and are deployed on a hyperledger channel. Chaincodes have APIs which can be used to expose the business logic. Currently chaincodes are supported in GO language. For this scenario, I have created a chaincode program which supports Read/Write/Search of product reviews.

You would need to have an. Archive file prepared with the below structure.

 

You can find my source code here in GitHub. Below are the three files which I am using.

Chaincode.yaml file contains the ID and version. Every time you make a change to the programs, you can update the version here and upload the archive file again.

Product_review.yaml file describes the HTTP interface to the chaincode

Product_review.go file contains the actual implementation of each of the operations in Go language.

You can find more info on packaging chaincode programs in SAP Help

There is a Hello World sample program which shows how to create a simple structure and use the READ/Write operations. I based my programs on top of the sample code and enhanced it for my requirements.

Note that in the Product_review.yaml file, the parameters have been defined fore each operation.

post:
      operationId: create
      summary: Creates a text by ID 
      parameters:
      - $ref: '#/parameters/id'
      - $ref: '#/parameters/text'
      - $ref: '#/parameters/review'
      - $ref: '#/parameters/name'
      - $ref: '#/parameters/location'
      - $ref: '#/parameters/rating'

In the Product_review.go file, I have defined a Doc structure as follows. Note that each structure fields start with a capital letter.

type Doc struct {
	Text string `json:"text"`
	Review string `json:"review"`
	Name string `json:"name"`
	Location string `json:"location"`
	Rating string `json:"rating"`
}

Below is the code snippet from the Product_review.go file.. I have implemented the search function to take the input of a product and provide search results which include elements from the structure.

func (cc *ProductReview) search(stub shim.ChaincodeStubInterface, args []string) peer.Response {

	searchString := strings.Replace(args[0], "\"", ".", -1) // protect against SQL injection
	queryString := fmt.Sprintf("{\"selector\": {\"text\": {\"$regex\": \"%s\"}}, \"fields\": [\"text\",\"review\",\"name\",\"location\",\"rating\"], \"limit\":99}", strings.Replace(searchString, "\"", ".", -1))
	resultsIterator, err := stub.GetQueryResult(queryString)
	if err != nil {
		return Error(http.StatusInternalServerError, err.Error())
	}
	defer resultsIterator.Close()

	// Write return buffer
	var buffer bytes.Buffer
	buffer.WriteString("{ \"values\": [")
	for resultsIterator.HasNext() {
		it, _ := resultsIterator.Next()
		if buffer.Len() > 15 {
			buffer.WriteString(",")
		}
		var doc Doc
		buffer.WriteString("{\"id\":\"")
		buffer.WriteString(it.Key)
		buffer.WriteString("\", \"review\":\"")
		buffer.WriteString(doc.FromJson(it.Value).Review)
		buffer.WriteString("\", \"product\":\"")
		buffer.WriteString(doc.FromJson(it.Value).Text)
		buffer.WriteString("\", \"name\":\"")
		buffer.WriteString(doc.FromJson(it.Value).Name)		
		buffer.WriteString("\", \"location\":\"")
		buffer.WriteString(doc.FromJson(it.Value).Location)
		buffer.WriteString("\", \"rating\":\"")
		buffer.WriteString(doc.FromJson(it.Value).Rating)
		buffer.WriteString("\"}")
	}
	buffer.WriteString("]}")

	return Success(http.StatusOK, "OK", buffer.Bytes())
}

It’s time to upload the chaincode program. Navigate to the chaincode menu.

Provide a zip file which contains all the relevant files.

Once you have deployed the zip file, you can test it by clicking on the “test chaincode”

This will open up a swagger window. Click on “Authorize” and provide the client ID and client secret captured earlier

Use the POST operation to add entries into the blockchain. You can use the GET operation to view the entries too.

Since our application is going to use blockchain to retrieve product reviews for a particular product, you can use the Search option with wildcard as shown below.

Testing using Postman REST Client

You can invoke the same APIs using Postman. We would first need to obtain an access token.

Use the GET method and provide the URL obtain during the creation of the authkey. Suffix the URL with “/oauth/token?grant_type=client_credentials”. For user name and password, provide client ID and secret. This request should provide you an access token. Make a note of it.

In a new window, use the GET method and provide the URL to invoke the search pattern function. I wasted 2 hours by using a POST method 🙁

URL: https://hyperledger-fabric.cfapps.eu10.hana.ondemand.com/api/v1/chaincodes/<chaincode_ID>/latest/search/ipod

For Authorization, add Bearer and <access token> and submit the request. This should return list of product reviews which match the search criteria.

Creating an application which invokes ML & Blockchain service

For the HTML5 app to invoke the ML or Blockchain APIs you would need to create destinations in the SAP CP Neo environment.

 

Create your destinations with the below URLs.

Token URL: https://cal.authentication.eu10.hana.ondemand.com/oauth/token

Service URL: https://hyperledger-fabric.cfapps.eu10.hana.ondemand.com/api/v1/chaincodes/<chaincode_ID>/latest/search

Authentication = NoAuthentication

Once your destinations have been setup, you can refer these destinations in your HTML5 app.

var tokenURL = "/blockchaintoken"
			var clientId = "<client-ID to be replaced>";
			var clientSecret = "<client-secret to be replaced";

			$.ajax({
				url: tokenURL + "?grant_type=client_credentials",
				type: "GET",
				contentType: "application/json",
				dataType: "json",
				async: false,
				beforeSend: function (xhr) {
					xhr.setRequestHeader("Authorization", "Basic " + btoa(clientId + ":" + clientSecret));
				},
				success: function (response) {
					debugger;
					accessToken = response.access_token;
				},
				timeout: 5000
			});


			var searchCondition = productInfo.toLowerCase();
			var serviceURL = '/blockchainservice';
			var productReviews = {};
			$.ajax({
				url: serviceURL + "/" + searchCondition,
				type: "GET",
				beforeSend: function (xhr) {
					xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
				},
				async: false,
				success: function (data) {
					try {
						debugger;
						var results = data.values;
						var productsInfo = {
							reviews: []
						};

						for (var i in results) {
							var item = results[i];
							productsInfo.reviews.push({
								"id": item.id,
								"location": item.location,
								"name": item.name,
								"rating": item.rating,
								"review": item.review,
								"product": item.product
							});
						}

						var oModel1 = new sap.ui.model.json.JSONModel(productsInfo);
						oModel1.setDefaultBindingMode("TwoWay");
						that.getView().setModel(oModel1);

					} catch (err) {
						MessageToast.show("Caught - [ajax error] :" + err.message);
					}
				},
				error: function (request, status, error) {
					MessageToast.show("Caught - [ajax error] :" + request.responseText);
				}
			});

Below is the final output of the HTML5 app which renders the output from the blockchain service APIs.

 

 

Assigned Tags

      8 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi Murali,

      i just checked my CF trial account, which is expiring in 26 days and may not be renewed after that, for Entitlements, but cannot see the same list as yours:

      do you know if there's a way to bump them up from 2 to 4 in the trial account?

      Thank you, greg

      Author's profile photo Murali Shanmugham
      Murali Shanmugham
      Blog Post Author

      Hi Gregory,

      Not sure. I believe the Blockchain Beta program terminated on 31-Aug-2018 in the SAP CP trial environment. I am using a productive Cloud Foundry account and hence it has additional entitlements.

       

      Author's profile photo Pratikkumar Modh
      Pratikkumar Modh

      I am getting below error
      directory structure is the same as mentioned above

       

       

      Author's profile photo Murali Shanmugham
      Murali Shanmugham
      Blog Post Author

      Hi, Can you please share a screenshot of your zip file content

       

      Author's profile photo Pratikkumar Modh
      Pratikkumar Modh

      Hi,
      Please download a file from below link

      https://drive.google.com/open?id=1iZjpNWUvtUz_jUuRVSHtUAl4MtXxcrjw

      let me know if any changes needed in a file

      Thanks

      Author's profile photo Saritha Koroth
      Saritha Koroth

      Hi Murali,

      Even I am getting the same chaincode deployment error.

      Please suggest.

      Regards,

      Saritha

       

      Author's profile photo Marius Obert
      Marius Obert

      Hi Murali,

       

      this is a nice POC and great summary of the service!

      Please be aware that you shouldn't use a UI5 app in a production scenario because everyone can see your tokens/keys and manipulate your data or chaincode.

       

      Thanks,

      Marius

      Author's profile photo Pooja Khandhadia
      Pooja Khandhadia

      Hi Murali,

       

      While creating the service instance i am getting this error. Can you please help me solving this.

       

      Thanks,

      Pooja