An Efficient Customized Blockchain System for Inter-Organizational Processes

We construct a blockchain system by embedding the customized process engine into the blockchain nodes based on a permissioned blockchain platform Hyperledger Fabric and a process engine Activiti. The customized process engine executes the inter-organizational business processes via a blockchain-style procedure, i.e., checking the validity of transactions, adding the valid transactions into the blockchain through the consensus mechanism, and then updating the process states according to the committed transactions.

Puwei Wang, Zhouxing Sun, Rui Li, Jinchuan Chen, Ping Gong, Xiaoyong Du, An Efficient Customized Blockchain System for Inter-Organizational Processes, IEEE International Conference on Web Services (ICWS), page 615-625, 2023

Prerequisites and setup

* Docker - v 20.10.7 or higher

* Docker Compose - v1.27.4 or higher

* Node.js v8.17.0

* Java 1.8

* [Download Docker images]

​ hyperledger/fabric-orderer:1.4

​ hyperledger/fabric-zookeeper:x86_64-0.4.6

​ hyperledger/fabric-kafka:x86_64-0.4.6

How To Use

1. Load our docker images

cd workflow-engine
docker load -i workflow-peer-v2
docker load -i workflow-ca

note:

2. Launch the blockchain system

2.1 Launch the network using docker-compose

cd workflow-engine
docker-compose -f workflow.yaml up
* 3 CAs
       IMAGE                                  NAMES
workflow-ca:1.0                         ca.org3.workflow.com
workflow-ca:1.0                         ca.org2.workflow.com
workflow-ca:1.0                         ca.org1.workflow.com

* An orderer with a kafka node and a zookeeper node
       IMAGE                                  NAMES
hyperledger/fabric-orderer:1.4.0           orderer.workflow.com
hyperledger/fabric-kafka:x86_64-0.4.6       kafka.workflow.com
hyperledger/fabric-zookeeper:x86_64-0.4.6   zookeeper.workflow.com

* 3 peers (1 peers per Org)
       IMAGE                                  NAMES
workflow-peer:latest                     peer0.org3.workflow.com
workflow-peer:latest                     peer0.org2.workflow.com
workflow-peer:latest                     peer0.org1.workflow.com

2.2 Install the fabric-client and fabric-ca-client node modules and start the node app on PORT 4000

cd workflow-engine/sdk-application
./runApp.sh

output

[2023-11-02 15:17:33.147] [INFO] SampleWebApp - ****************** SERVER STARTED ************************
[2023-11-02 15:17:33.151] [INFO] SampleWebApp - ***************  http://localhost:4000  ******************

2.3 Create Channel

cd workflow-engine/sdk-application
./createChannelAndJoin.sh

output

{"channels":[{"channel_id":"workflowchannel"}]}

note

2.4 Start workflow-engine service And Nacos

docker exec peer0.org1.workflow.com sh /usr/local/scripts/wfServiceScripts/wfServiceStart.sh &
docker exec peer0.org2.workflow.com sh /usr/local/scripts/wfServiceScripts/wfServiceStart.sh & 
docker exec peer0.org3.workflow.com sh /usr/local/scripts/wfServiceScripts/wfServiceStart.sh & 
docker exec peer0.org1.workflow.com sh /usr/local/scripts/nacosScripts/nacosStart.sh &

output

…
2023-11-02 04:22:45,333 INFO Nacos Log files: /nacos/logs/
2023-11-02 04:22:45,334 INFO Nacos Conf files: /nacos/conf/
2023-11-02 04:22:45,336 INFO Nacos Data files: /nacos/data/
2023-11-02 04:22:45,337 INFO Nacos started successfully in cluster mode.
docker exec peer0.org2.workflow.com sh /usr/local/scripts/nacosScripts/nacosStart.sh &
docker exec peer0.org3.workflow.com sh /usr/local/scripts/nacosScripts/nacosStart.sh &

3.Create and register services

cd workflow-engine/testService
mvn clean package
cd target
java -jar testService.jar --server.port=${service port}
#example
java -jar testService.jar --server.port=6666
curl --request POST \
  --url http://{service IP}:{service port}/test \
  --header 'content-type: application/json' \
  --data '{
    "aaa":"bbb"
}'
#example
curl --request POST \
  --url http://10.47.33.219:6666/test \
  --header 'content-type: application/json' \
  --data '{
    "aaa":"bbb"
}'
curl -X POST 'http://{localhost IP}:{port of nacos}/nacos/v1/ns/instance?port={service port}&healthy=true&ip={service IP}&weight=1.0&serviceName={serviceGroup}@@{serviceName}&encoding=GBK'
#example
curl -X POST 'http://127.0.0.1:7848/nacos/v1/ns/instance?port=6666&healthy=true&ip=10.47.33.219&weight=1.0&serviceName=WORKFLOW@@testService&encoding=GBK'

note

ServiceGroup can be left blank and used the default value, directly as serviceName={serviceName};

The service IP cannot be 127.0.0.1 or localhost; it needs to be a specific IP address.

4.Edit the bpmn diagram

cd workflow-engine/bpmn-vue
npm install
npm run dev

​ General-Details-*Implementation*: Java Class

​ General-Details-*Java Class*: com.wq.wfEngine.taskService.web

5.Deploy the bpmn diagram

curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/wfRequest/deploy \
  --header 'content-type: multipart/form-data' \
  --form file=@{path of bpmn file}\
  --form deploymentName={workflow name}
#example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/wfRequest/deploy \
  --header 'content-type: multipart/form-data' \
  --form file=@/users/dreamingworld/Fabric/workflow-engine/simpleSample.bpmn \
  --form deploymentName=simpleSample.bpmn

output

{
	"code": 200,
	"Oid": "simpleSample.bpmn",
	"body": "等待上链,更改状态",
	"模拟执行结果": true
}
#The response will indicate successful execution and await writing into the blockchain. It will include an attribute called Oid, which can be used to check whether the write operation was successful or not
curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/queryDeployments
#example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/queryDeployments

output

Oids of deployed bpmn diagrams, ["simpleSample.bpmn"]

6.instantiate a BPMN diagram

curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/wfRequest/instance \
  --header 'content-type: application/json' \
  --data '{
    "deploymentName":"{bpmn oid}",
    "businessData":"{}",
    "processData":"{}",
    "staticAllocationTable":"{ the task allocation table used to assign executors for user tasks }"
}'
#example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/wfRequest/instance \
  --header 'content-type: application/json' \
  --data '{
    "deploymentName":"simpleSample.bpmn",
    "businessData":"{}",
    "processData":"{}",
    "staticAllocationTable":"{\"submit\":\"sun\"}"
}'
curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/queryStatusByDeploymentName/{deploymentName}
#example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/queryStatusByDeploymentName/simpleSample.bpmn

output

[ 
	{
		"oid": "simpleSample.bpmn@0f513fc9-3a9e-40cf-8ffb-3d5bbf88c62f",
		"tasks": ["submit"]
	}
]

7.dynamic BInd

Dynamic binding allows the registered service to be dynamically bound to the service task in the workflow instance, or for the executor to be dynamically assigned to the user task.

curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/userDynamicBind \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data oid={oid} \
  --data taskName={taskName} \
  --data user={userName}
#example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/userDynamicBind \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data oid=simpleSample.bpmn@0f513fc9-3a9e-40cf-8ffb-3d5bbf88c62f \
  --data taskName=submit \
  --data user=testone
curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/serviceDynamicBind \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data oid={oid of bmpn instance} \
  --data taskName={task} \
  --data serviceName={serviceName} \
  --data httpMethod={httpMethod} \
  --data route={route} \
  --data '{input}' \
  --data serviceGroup={serviceGroup}
# example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/serviceDynamicBind \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data oid=simpleSample.bpmn@0f513fc9-3a9e-40cf-8ffb-3d5bbf88c62f \
  --data taskName=task3 \
  --data serviceName=testService \
  --data httpMethod=POST \
  --data route=/test \
  --data 'input={"ID":"init.ID","Address":"sun.Address"}' \
  --data serviceGroup=WORKFLOW

Property description of serviceTask

8.Execute the userTask

curl --request POST \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/wfRequest/complete \
  --header 'content-type: application/json' \
  --data '{
    "Oid":"{oid}",
    "taskName":"{taskName}",
    "businessData":"{businessData in JSON format}",
    "processData":"{processData in JSON format}",
    "user":"{the executor who is assigned to execute the user task}"
}'
#example
curl --request POST \
  --url http://127.0.0.1:8999/grafana/wfRequest/complete \
  --header 'content-type: application/json' \
  --data '{
    "Oid":"simpleSample.bpmn@0f513fc9-3a9e-40cf-8ffb-3d5bbf88c62f",
    "taskName":"submit",
    "businessData":"{\"ID\":\"001\", \"Name\":\"Wang\", \"Address\":\"Beijing\"}",
    "processData":"{}",
    "user":"testone"
}'

output

{
"code":200,
"Oid":"simpleSample.bpmn@0f513fc9-3a9e-40cf-8ffb-3d5bbf88c62f",
"body":"等待上链,更改状态",
"模拟执行结果":true
}

9.Get the response(execution result)

curl --request GET \
  --url http://{localhost IP}:{port of workflow engine service}/grafana/getResponseByOid/{Oid}

#example
curl --request GET \
  --url http://127.0.0.1:8999/grafana/getResponseByOid/simpleSample.bpmn@0f513fc9-3a9e-40cf-8ffb-3d5bbf88c62f

output

{
"startPutToBlockChain":1698925187420,
"toTaskName":"[]",
"isDeploy":false,
"flushStartTime":1698925187836,
"businessData":"{\"Address\":\"Beijing\",\"ID\":\"001\"}",
"fromTaskName":"[submit]",
"deploymentName":"simpleSample.bpmn",
"startTime":1698925185877,
"flushEndTime":1698925188053,
"isEnd":true,
"simulationEndTime":1698925187187
}

Property description of the response

property's name description
startPutToBlockChain The time at which data writing to the blockchain begins
isDeploy Indicates whether the deployment process has taken place or not
flushStartTime The time when the data has been written to the blockchain and the state database starts to change
isEnd Indicates whether the workflow instance has ended or not
toTaskName The name of the next user task
businessData The response containing business-related information
fromTaskName The name of the completed user task
deploymentName The deployment name of the workflow instance
startTime The time at which the request handling begins
flushEndTime The time when the state database has completed its changes
simulationEndTime The time at which the simulation has been completed.