去中心化的业务支撑系统开发,一样可设计为可扩展的项目开发流程。通常设计为三层架构。
1、底层存储。底层使用区块链保证交易的安全性和不可篡改性。平台可以是EEA系列、Hyperledger Fabric、商业化的Hyperchain等主流的区块链平台。核心的业务逻辑全部用智能合约或链码实现,并把智能合约部署到区块链上运行。在底层存储中使用数据库是为了对区块链数据做一个完整的备份,实现灾备。同时,因为行业内目前还没有很好的区块链可视化的解决方案,所以加入数据库可以间接查看区块链的数据。在实际开发中,可以进行区块链和数据库的双写,以实现数据的同步。
2、后端系统。中间层作为上层应用和底层区块链的桥接。后端系统的开发,可以使用不同的接口和区块链进行交互,常见的有Json-RPC接口和web3.js接口。如果使用Java作为后端,则可以选择Json-RPC;如果使用Node.js作为后端,则可以选择web3.js。由于关键的合约逻辑都已经在智能合约中完成,故后端系统的功能开发主要发力于数据的编、解码、数据转发,以及为上层提供REST ful接口调用 。
3、上层客户端界面。看实际项目的需求分析,并通过中间层提供的REST ful接口和区块链交互,可以把上层界面做成web页面、PC桌面、移动手持端等,方便系统交割后用户使用。
这是一种轻客户端的设计方案,也是MVC经典架构在区块链应用开发上的演绎。客户端不需要知道底层区块链相关的加密解密、解码编码、记账同步等等复杂操作或烦琐流程,上层界面应用面向接口编程,只需要调用处理RESTful返回的Json数据并展示。
分层应用开发,能够把耦合度降至最低,减少当下代码迭代修改或功能变更中的不利影响,方便后续系统扩展和维护,满足高质量的软件工程属性。在项目管理中,有利于模块划分,有利于安排多人并行开发,不同层次的开发任务可以让不同的开发人员进行设计实现,对接容易,提高了开发效率。
附录、VSCode-1.36 launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "orderer0.example.com",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2345,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/orderer",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
"FABRIC_CFG_PATH":"${workspaceRoot}/cfg/fabric",
"ORDERER_GENERAL_LOGLEVEL": "debug",
"ORDERER_GENERAL_LISTENADDRESS": "0.0.0.0",
"ORDERER_GENERAL_GENESISMETHOD": "file",
"ORDERER_GENERAL_GENESISFILE": "${workspaceRoot}/cfg/fabric/channel-artifacts/genesis.block",
"ORDERER_GENERAL_LOCALMSPID": "OrdererMSP",
//"ORDERER_GENERAL_LOCALMSPDIR": "${workspaceRoot}/cfg/fabric/msp",
//"ORDERER_GENERAL_LOCALMSPDIR":"${workspaceRoot}/cfg/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp",
"ORDERER_GENERAL_LOCALMSPDIR":"${workspaceRoot}/cfg/fabric/crypto-config/ordererOrganizations/example.com/users/[email protected]/msp",
"ORDERER_FILELEDGER_LOCATION":"${workspaceRoot}/var/prodka/orderer",
//"ORDERER_GENERAL_GENESISPROFILE":"SampleDevModeSolo",
//"ORDERER_GENERAL_GENESISPROFILE":"SampleInsecureKafka",
"ORDERER_GENERAL_GENESISPROFILE":"TwoOrgsOrdererGenesis",
//"CONFIGTX_ORDERER_ORDERERTYPE":"kafka"
},
"args": [],
"output": "${workspaceRoot}/bin/orderer0.example.com",
//"backend": "native"
},
{
"name": "orderer1.example.com",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2345,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/orderer",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
"FABRIC_CFG_PATH":"${workspaceRoot}/cfg/fabric",
"ORDERER_GENERAL_LOGLEVEL": "debug",
"ORDERER_GENERAL_LISTENADDRESS": "0.0.0.0",
"ORDERER_GENERAL_LISTENPORT": "17050",
"ORDERER_GENERAL_GENESISMETHOD": "file",
"ORDERER_GENERAL_GENESISFILE": "${workspaceRoot}/cfg/fabric/channel-artifacts/genesis.block",
"ORDERER_GENERAL_LOCALMSPID": "Order1MSP",
"ORDERER_GENERAL_LOCALMSPDIR":"${workspaceRoot}/cfg/fabric/crypto-config/ordererOrganizations/example.com/users/[email protected]/msp",
//"ORDERER_GENERAL_GENESISPROFILE":"SampleDevModeSolo",
//"ORDERER_GENERAL_GENESISPROFILE":"SampleInsecureKafka",
"ORDERER_GENERAL_GENESISPROFILE":"TwoOrgsOrdererGenesis",
"ORDERER_FILELEDGER_LOCATION":"${workspaceRoot}/var/prodkaf/orderer",
//"ORDERER_FILELEDGER_LOCATION":"/var/hyperledger/prod1/orderer"
},
"args": [],
"output": "${workspaceRoot}/bin/orderer1.example.com",
//"backend": "native"
},
{
"name": "org1.example.com",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2347,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/peer",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
"FABRIC_CFG_PATH":"${workspaceRoot}/cfg/fabric",
"CORE_PEER_ADDRESS":"peer0.org1.example.com:7051",
"CORE_PEER_LISTENADDRESS":"peer0.org1.example.com:7051",
"CORE_PEER_EVENTS_ADDRESS":"peer0.org1.example.com:7053",
"CORE_PEER_NETWORKID":"clxdev",
"CORE_CHAINCODE_EXECUTETIMEOUT":"3000s",
"CORE_PEER_FILESYSTEMPATH":"${workspaceRoot}/var/prodka",
"CORE_PEER_MSPCONFIGPATH":"${workspaceRoot}/cfg/fabric/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp",
"CORE_PEER_LOCALMSPID":"Org1MSP",
//"CORE_PEER_ID" : "Org1MSP",
"CORE_PEER_ID" : "peer0.org1.example.com"
"CORE_PEER_GOSSIP_EXTERNALENDPOINT":"peer0.org1.example.com:7051"
},
//"args": ["version"],
"args": ["node","start","--peer-chaincodedev=true","--logging-level=DEBUG"],
"output": "${workspaceRoot}/bin/peer",
},
{
"name": "org2.example.com",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2347,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/peer",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
"FABRIC_CFG_PATH":"${workspaceRoot}/cfg/fabric",
"CORE_PEER_ADDRESS":"peer0.org2.example.com:17051",
"CORE_PEER_LISTENADDRESS":"peer0.org2.example.com:17051",
"CORE_PEER_EVENTS_ADDRESS":"peer0.org2.example.com:17053",
"CORE_PEER_NETWORKID":"clxdev",
"CORE_CHAINCODE_EXECUTETIMEOUT":"3000s",
"CORE_PEER_FILESYSTEMPATH":"${workspaceRoot}/var/prodkaf",
"CORE_PEER_MSPCONFIGPATH":"${workspaceRoot}/cfg/fabric/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp",
"CORE_PEER_LOCALMSPID":"Org2MSP",
//"CORE_PEER_ID" : "Org2MSP",
"CORE_PEER_ID" : "peer0.org2.example.com",
"CORE_PEER_GOSSIP_EXTERNALENDPOINT":"peer0.org2.example.com:17051"
},
//"args": ["version"],
"args": ["node","start","--peer-chaincodedev=true","--logging-level=DEBUG"],
"output": "${workspaceRoot}/bin/org2.example.com",
},
{
"name": "peer chaincode invoke",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2349,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/peer",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
},
"args": ["chaincode", "invoke", "-n=mycc", "-c={\"Args\":[\"invoke\",\"a\",\"b\",\"5\"]}","-o=127.0.0.1:7050", "-C=ka1", "--logging-level=DEBUG"],
//"args": ["chaincode", "query", "-n=mycc", "-c={\"Args\":[\"query\",\"a\"]}","-o=127.0.0.1:7050", "-C=ch1", "--logging-level=DEBUG"],
"output": "${workspaceRoot}/bin/cli",
},
{
"name": "cc chaincode_example02",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2351,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02/chaincode_example02.go",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
"CORE_PEER_ADDRESS":"127.0.0.1:7051",
"CORE_CHAINCODE_LOGGING_LEVEL":"debug",
"CORE_CHAINCODE_ID_NAME":"mycc:0",
//"CORE_CHAINCODE_ID_NAME":"mycc:1.0",
"CORE_CHAINCODE_EXECUTETIMEOUT":"3000s" //temp for debug
},
// "buildFlags": "-gcflags '-N -l -m' -ldflags '-X CORE_PEER_ADDRESS=127.0.0.1:7051 '",
//"showLog": true,
"args": [],
"output": "chaincode_example02"
},
{
"name": "ccka chaincode_example02",
"type": "go",
"request": "launch",
"mode": "debug",
"remotePath": "",
"port": 2351,
"host": "127.0.0.1",
"program": "${workspaceRoot}/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02/chaincode_example02.go",
"env": {
"GOPATH":"${workspaceRoot}:/opt/go/gopath",
"CORE_PEER_ADDRESS":"127.0.0.1:7051",
"CORE_CHAINCODE_LOGGING_LEVEL":"debug",
"CORE_CHAINCODE_ID_NAME":"myccka:0",
"CORE_CHAINCODE_EXECUTETIMEOUT":"3000s" //temp for debug
},
"args": [],
"output": "chaincode_example02_ka"
},
]
}