Skip to Content

The following steps will explain how to integrate SAP Leonardo Blockchain using MultiChain with an SAP Cloud Platform side-by-side extension using the SAP S/4HANA Cloud SDK.

Updated Oct 2018: Using MultiChain became even more simple! Newly added MultichainService class is the key. See below!

Be aware: At the time of writing the SAP Cloud Platform Blockchain MultiChain service is available to customers, but not to trial account users (2018-09-07). The SAP Cloud Platform Hyperledger Fabric service is available to trial account users, and there is a blog post explaining integration of SAP Cloud Platform Hyperledger Fabric in your side-by-side extension.

Note: This post is part of a series. For a complete overview visit the SAP S/4HANA Cloud SDK Overview. Furthermore, an extended version of this blogpost is part of the book Extending SAP S/4HANA.

Goal of this Blog Post

This blog post covers the following steps:

  1. Introduce the concept of SAP Cloud Platform Blockchain and its technology variant MultiChain and point out their significance.
  2. Build a microservice writing to and reading from a MultiChain blockchain on SAP Cloud Platform Blockchain.

SAP Cloud Platform Blockchain using MultiChain

Blockchain is a concept and an architecture based on distributed ledger technology to record and share data across a multi-party network. It integrates data from multiple sources and creates a single, trustful truth. In doing so, it promises to provide powerful advantages for businesses, leading to increased efficiency and simplified processes.

Cases such as Blockchain-based pallet management and Farm to Consumer traceability implemented by SAP showcase the potential. Blockchain will change the way we do business – from point to point interaction to a true network of business objects and entities.

SAP drives the value-adding Blockchain with products such as SAP Cloud Platform Blockchain, which provides maximum flexibility with the support of multiple advanced blockchain technologies like Hyperledger Fabric and MultiChain. In this article you will learn how to integrate one of those technologies with your S/4HANA side-by-side extension: MultiChain. The availability of multiple technologies provides you options to follow and be on top of the continuing development of blockchain technology.

Outline of this post

The post will help you to set up the technical integration with between a S/4HANA side-by-side extension on the SAP Cloud Platform and the SAP Cloud Platform MultiChain Blockchain service. The first step will be creating a skeleton side-by-side extension project and deploying it on the SAP Cloud Platform to test the viability of your development environment and create the application’s environment on the SAP Cloud Platform to which blockchain services can be bound. Then the required SAP Cloud Platform Blockchain service will be created and bound to the application. Finally the access to the Blockchain service will be added to the Java code of the side-by-side extension.

Creating the side-by-side extension

The starting point is the generation of the hello-world application template with maven (see Step 3 https://blogs.sap.com/2017/05/19/step-3-with-sap-s4hana-cloud-sdk-helloworld-on-scp-cloudfoundry/ for a detailed introduction):

mvn archetype:generate -DarchetypeGroupId=com.sap.cloud.s4hana.archetypes \
  -DarchetypeArtifactId=scp-cf-tomee -DarchetypeVersion=LATEST

The project is directly runnable after its creation: A hello world servlet is provided for quick and easy testing. This is what we will leverage now to quickly continue setting up and testing our environment. Compile and run the code for a quick initial test (in application subdirectory):

mvn package

mvn tomee:run  
# or: mvn tomee:debug

The service should be accessible at http://localhost:8080/hello . Continue to deploy it to SAP Cloud Platform (in main directory, where manifest.yml is located):

cf push

The application host name will be provided by the output on the command line (mine was named: multichain-cf-blog-crawly-roturier.cfapps.sap.hana.ondemand.com, making it accessible at http://multichain-cf-blog-crawly-roturier.cfapps.sap.hana.ondemand.com/hello – SAP-internal URL, not accessible outside).

Create the required blockchain service

On SAP Cloud Platform you have a wide variety of services you can choose to use in your applications. A couple of them belong to SAP Cloud Platform Blockchain:

  • MultiChain
  • Hyperledger Fabric Node
  • Hyperledger Fabric …

For this blog post we’ll use the MultiChain service of SAP Cloud Platform Blockchain. It is a leaner Blockchain platform, focusing on support of digital assets and using the Blockchain as a log of information. So if your use case only requires digital assets or storing hashes in a tamper-proof and timestamped log, then MultiChain is for you! If on the other hand you need a full-fledged smart contract platform then I recommend you to divert your attention to SAP Cloud Platform Hyperledger Fabric – there is a similar blog post available: Deep Dive 14 – Integrate SAP Cloud Platform Blockchain using Hyperledger Fabric into a S/4HANA Cloud SDK application.

In a sign of its simplicity when compared to Hyperledger Fabric, MultiChain only requires one service to be set up and bound to your application.

Go to the application overview screen for your newly deployed side-by-side extension skeleton app. You can find it in the SAP Cloud Platform Cockpit for production – at this time the service is not available on the trial edition.

Now go to the ‘Service Bindings’ screen, and hit the button ‘Bind Service’. In the opening dialog select to add the service from the catalog, and search for ‘multichain’ in the search form:

In the following screens select the service plan you would like to use – at the time of writing it was ‘dev’. Then go ahead without specifying specific parameters, choose a service name, and finish the binding.

Read and write to the MultiChain service from the SAP S/4HANA Cloud SDK side-by-side extension

Open the project skeleton generated before with your favorite IDE, and browse to the HelloWorldServlet. You can generate project files with maven, too:

# in main directory:
mvn install 
# install is required to make eclipse:eclipse or idea:idea work

mvn eclipse:eclipse

mvn idea:idea

The SAP S/4HANA Cloud SDK provides the MultichainService class to facilitate access to the SAP Cloud Platform Blockchain MultiChain service. It makes use of other facilities provided by the SAP S/4HANA Cloud SDK: ScpCfServiceInfo and reusable HTTP clients.

With this class creating code that uses MultiChain functionality in your application becomes very easy. In the given example data is written to and read from the default stream. Keys are employed to make the stream usable like a key-value store. Please find further information in the official MultiChain API reference .

To use the class add the dependency to the application/pom.xml file:

...
        <dependency>
            <groupId>com.sap.cloud.s4hana</groupId>
            <artifactId>s4hana-all</artifactId>
        </dependency>

        <!-- Dependency added for SAP Cloud Platform MultiChain service access facilitation -->
        <dependency>
            <groupId>com.sap.cloud.s4hana.services</groupId>
            <artifactId>scp-blockchain</artifactId>
        </dependency>
...

To create the servlet, copy the HelloWorldServlet class to a new servlet named, for example, MultichainServlet. Modify the @WebServlet annotation to register the servlet on a new path, say @WebServlet("/multichain") . Then change the doGet method to read:

String key = request.getParameter("key");
if (Strings.isNullOrEmpty(key)) {
    response.setStatus(HttpStatus.SC_BAD_REQUEST);
} else {

    try {
        MultichainService multichainService = MultichainService.create();

        String valueHex = request.getParameter("valueHex");
        final Object result;
        if (valueHex != null) {
            result = multichainService.invoke(
                    "publish", "root", key, valueHex);
            logger.debug("Publish result: {}", result);
        } else {
            result = multichainService.invoke(
                    "liststreamkeyitems", "root", key);
            logger.debug("listtreamkeyitems result: {}", result);
        }

        response.getWriter().write(new Gson().toJson(result));
        
    } catch (Exception e) {
        final String msg = 
                "Failed to access MultiChain service: " + e.getMessage();

        logger.error(msg, e);

        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.getWriter().println(msg);
    }
}

With this code the servlet provides a straightforward interface for reading and writing hexadecimal data to the ‘root’ default stream of the MultiChain Blockchain accessible via Cloud Foundry service information.

First the key parameter is read from the request. Then an instance of the MultichainService class is created that facilitates access to the MultiChain API. This class is available in the com.sap.cloud.s4hana.services:scp-blockchain dependency added above in this blog and you should have added it when following this blog from top to bottom.

Next the valueHex parameter is read. It’s presence determines the fact that a write operation is requested. If the parameter is not present in the request, then a read operation is undertaken.

The MultiChain API commands requested can be found in the MultiChain API reference : publish allows writing a value entry under the given key in the given stream. Here we use the ‘root’ stream, which is available by default in any MultiChain installation. Be aware that the MultiChain API requires data to be in hexadecimal format – this is very fitting for the main use of this blockchain data facility: Writing hashes to the chain. Hashes are regularly printed in human-readable hex code, instead of their raw byte values. The result of this operation will be the id of the created transaction.

liststreamkeyitems gets all entries under a specific key in a specific stream. It will list everything ever written under the key together with the id of the transaction that was created by a write operation. See below for an example of the output. But let’s produce the output ourselves, too: Now you can compile and run the code for a quick initial test (in application subdirectory):

mvn package

export ALLOW_MOCKED_AUTH_HEADER=true 
# or windows: set ALLOW_MOCKED_AUTH_HEADER=true

# VCAP_SERVICES needs mocking too if you test locally.
# Get the values for the locations marked <EDIT> from the SAP Cloud Platform Cockpit in the application screen under environment variables:
export VCAP_SERVICES='{ "multichain": [ { "name": "multichain_test", "instance_name": "multichain_test", "binding_name": null, "credentials": { "api_key": "<EDIT>", "url": "<EDIT>" }, "syslog_drain_url": null, "volume_mounts": [], "label": "multichain", "provider": null, "plan": "dev", "tags": [ "blockchain", "multichain" ] } ] }'

# on windows: set VCAP_SERVICES={ "multichain": [ { "name": "multichain_test", "instance_name": "multichain_test", "binding_name": null, "credentials": { "api_key": "<EDIT>", "url": "<EDIT>" }, "syslog_drain_url": null, "volume_mounts": [], "label": "multichain", "provider": null, "plan": "dev", "tags": [ "blockchain", "multichain" ] } ] }

mvn tomee:run  
# or: mvn tomee:debug

The service should now be accessible at http://localhost:8080/multichain?key=k1 . You can even deploy your application to SAP Cloud Platform (in main directory, where manifest.yml is located):

cf push

Be aware that also here, if you don’t set up the security environment required for production that provides tenant information (see Secure your application on SAP Cloud Platform Cloud Foundry ) you will need to mock auth headers:

# show your apps in current space - this assumes you deployed the skeleton as recommended above
cf apps 

cf set-env <enter your app name> ALLOW_MOCKED_AUTH_HEADER true

# after the change of the env variable you need to restart the application:
cf restart <enter your app name>

The application host name will be provided by the output on the command line (mine was named: multichain-cf-blog-crawly-roturier.cfapps.sap.hana.ondemand.com, making it accessible at http://multichain-cf-blog-crawly-routrier.cfapps.sap.hana.ondemand.com/multichain?key=k1 – SAP-internal URL, not accessible outside ).

The resulting microservice is very simple but hopefully very transparent and instructive. Here is a test from a browser:

In the example you can see you can see two results stored under one key. You’ll see that the order is oldest->newest, verifiable with the ‘blocktime’ property. By the way, it’s a unix timestamp and an entry without blocktime is not yet confirmed and written onto the blockchain. See for example ‘getmempoolinfo’ in the MultiChain API reference regarding this.

To write to the blockchain use for example this query parameters:

?key=k1&valueHex=aa

Now go and write cool applications with these features!

 

A simple first addition would be a parameter ‘value’ with which non-hex-encoded strings can be used. Hint: This is how you handle hex with Google Guava:

String input = "test text";
final String hexEncoded = 
  BaseEncoding.base16().encode(input.getBytes("UTF-8"));
String decoded = 
  new String(BaseEncoding.base16().decode(hexEncoded), Charsets.UTF_8);
assertEquals(input, decoded);

 

For your reference here you can find complete code for the servlet:

import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.services.scp.blockchain.multichain.MultichainService;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/multichain")
public class MultichainServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;
    private static final Logger logger = CloudLoggerFactory.getLogger(MultichainServlet.class);

    @Override
    protected void doGet( final HttpServletRequest request, final HttpServletResponse response )
            throws IOException
    {
        logger.info("I am running!");

        String key = request.getParameter("key");
        if (Strings.isNullOrEmpty(key)) {
            response.setStatus(HttpStatus.SC_BAD_REQUEST);
        } else {

            try {
                MultichainService multichainService = MultichainService.create();

                String valueHex = request.getParameter("valueHex");
                final Object result;
                if (valueHex != null) {
                    result = multichainService.invoke(
                            "publish", "root", key, valueHex);
                    logger.debug("Publish result: {}", result);
                } else {
                    result = multichainService.invoke(
                            "liststreamkeyitems", "root", key);
                    logger.debug("listtreamkeyitems result: {}", result);
                }

                response.getWriter().write(new Gson().toJson(result));

            } catch (Exception e) {
                final String msg =
                        "Failed to access MultiChain service: " + e.getMessage();

                logger.error(msg, e);

                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().println(msg);
            }
        }
    }
}
To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply