APP
Hyperledger Composer上实现基于区块链的投票应用程序教程
2020-03-23 21650 0

Hyperledger Composer是一个广泛的开放式开发工具集和框架,可简化开发区块链应用程序的过程。Composer支持现有的Hyperledger Fabric区块链基础架构,使用Composer轻松创建区块链环境。我们只关注生成我们的业务网络存档(.bna)的模型,脚本和访问控制文件。准备好将Business Network Archive文件部署在存在Hyperledger Fabric和Node.js的分布式分类帐上。在那之后,我们只开发了一个web接口,它使用了我们想要的Rest API语言。



安装先决条件:



下面介绍如何在Hyperledger Composer上实现基于区块链的投票应用程序。对于Hyperledger Composer,我们需要检查是否具备Compose所需的所有先决条件,如果没有以下条件,则需要安装;Docker Engine,Docker-Compose,Node,npm,git,Python和VSCode(这不是必需的,但很有用)。



安装开发环境:



如果我们确定已安装了先决条件,则将继续安装要使用的开发环境。我们从安装开发Composer时所需的有用的CLI工具(composer-cli,必不可少的generator-hyperledger-composer,composer-rest-server和Yeoman)开始。然后,我们需要安装Hyperledger Fabric来部署我们的业务网络。此处说明了如何安装我们上面介绍的CLI工具和Hyperledger Fabric。



然后,通过这些命令激活Hyperledger Fabric。



cd ~/fabric-dev-servers
export FABRIC_VERSION=hlfv11
./startFabric.sh
./createPeerAdminCard.sh



就这样,所有的安装步骤都完成了。



Hyperledger Composer项目:



我们从业务网络定义的开发开始,这是我们正在构建的关键概念。根据官方文档,它定义为“业务网络定义是Hyperledger Composer编程模型的关键概念。它们由BusinessNetworkDefinition类表示,该类在composer-common模块中定义,并由composer-admin和composer-client导出。下图完美显示了BNA的各个部分,我们将根据需要对其进行更改。

我们应该对上图中可以看到的文件进行一些更改。但是我们通过使用Yeoman并遵循以下步骤来创建业务网络结构:

yo hyperledger-composer:businessnetwork

1. Enter vote-network as network name and desired information for description, author name, and author email
2. Select Apache-2.0 as the license
3. Enter org.example.empty
4. Select No when asked whether to generate an empty network

商业网络由资产,参与者,交易,访问控制规则以及可选的事件和查询组成,如您所见。因此我们进行以下修改。

Model File(.cto): 它包含所有资产,参与者和交易的类定义,我们对它们进行如下建模;

namespace org.example.empty
asset Vote identified by voteID {
o String voteID
--> Candidate candidate
}
participant Candidate identified by candidateId {
o String candidateId
o String firstName
o String lastName
}
transaction VoteLog {
o String voteID
--> Candidate candidate
}

Script File(.js): 它包含在事务发生时执行的事务处理器函数。

/**
* @param {org.example.empty.VoteLog} tx
* @transaction
*/
async function logAdd(tx) {
let assetRegistry = await getAssetRegistry('org.example.empty.Vote');
var factory = getFactory()
var asset = factory.newResource('org.example.empty', 'Vote', tx.voteID)
asset.candidate = tx.candidate
awai

Access Control(.acl):它包含基本的访问控制规则。

/**
* Access control rules for vote-network
*/
rule Default {
description: "Allow all participants access to all resources"
participant: "ANY"
operation: ALL
resource: "org.example.empty.*"
action: ALLOW
}

rule SystemACL {
description: "System ACL to permit all access"
participant: "ANY"
operation: ALL
resource: "org.hyperledger.composer.system.**"
action: ALLOW
}

生成并部署到业务网络存档:

定义业务网络后,必须导航到vote network目录(或输入了其他名称的目录)并运行以下命令,将其打包为可部署的业务网络存档(.bna)文件;

composer archive create -t dir -n

现在我们在vote-network目录中创建了一个名为vote-network@0.0.1.bna的业务网络存档文件,我们需要开始将其部署到Hyperledger Fabric。我们将再次导航到vote-network目录并按顺序运行命令。

注意:如果您已经创建了其他名称,则需要更改vote-network的名称

安装业务网络

composer network install --card PeerAdmin@hlfv1 --archiveFile vote-network@0.0.1.bna

启动业务网络

composer network start --networkName vote-network
--networkVersion 0.0.1 --networkAdmin admin
--networkAdminEnrollSecret adminpw --card PeerAdmin@hlfv1
--file networkadmin.card

将网络管理员身份导入为可用的名片

composer card import --file networkadmin.card

生成REST服务器:

此时Hyperledger Composer提供了一个REST Server,我们将参考在先前步骤中建模和定义的BND生成它。我们将再次导航到vote-network目录并按顺序运行命令。

composer-rest-server
1. Enter admin@vote-network as card name
2. Select never use namespaces
3. Select No when asked whether to secure the generated API
4. Select Yes when asked whether to enable event publication
5. Select No when asked whether to enable TLS security

之后生成的API将通过http://localhost:3000地址连接到已部署的区块链和业务网络。下图显示了端点的外观。

我们应该安装的所有东西都已完成。现在我们可以开发一个网页并连接到REST Server。该应用程序有2个版本(其中一个使用jQuery框架开发,另一个使用React框架开发),将分别进行解释。

jQuery版本:

根据官方网站,jQuery是一个快速、小型、功能丰富的JavaScript库。它用于向Hyperledger Composer提供的REST服务器发出post和get请求。

当任何候选人被选为投票时,结果会显示出来,如下所示;

这是jQuery代码;

<html lang="en">
<head>
<meta charset="utf-8">
<title>Blockchain Vote App</title>





</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm-12"><h2>Hyperledger Composer Vote Application</h2></div>
<div class="col-sm-12 row" id="dvAlert"></div>
<div class="col-sm-12 row d-flex justify-content-center" id="dvCandidates"></div>
</div>
</div>

<div class="modal" id="modalResult" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<canvas id="resultChart" width="100px" height="100px"></canvas>
</div>
</div>
</div>
</div>

<script>
var candidateList = [];
$(document).ready(function(){
$.get("http://localhost:3000/api/Candidate", function(data){
var html = '';
for(i=0;i<data.length;i++){
candidateList.push(data[i]);

html += '<div class="col-sm-4" style="text-align: center; padding: 5px; border-style: solid; border-width: 2px;">';
html += '<img src="image/user.png" class="rounded mx-auto d-block" style="width: 100px; height: 100px;">';
html += '<a class="btn btn-primary candidateSelect" data-name="' + data[i].firstName + '" data-value="' + data[i].candidateId + '" style="margin-top: 2px;">' + data[i].firstName + ' ' + data[i].lastName + '</a></div>';
}
$("#dvCandidates").empty();
$("#dvCandidates").html(html);

$(".candidateSelect").on("click", function(){
var candidateID = $(this).data("value");
var candidateName = $(this).data("name");

var param = {
"$class": "org.example.empty.VoteLog",
"voteID": new Date().getTime().toString(),
"candidate": "resource:org.example.empty.Candidate#" + candidateName,
"transactionId": null,
"timestamp": new Date().toString()
};

$.post("http://localhost:3000/api/VoteLog/", param, function(data){
$("#dvAlert").html('<div class="alert alert-success" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><strong>Success!</strong> You have used your vote in successfully! </div>');
window.setTimeout(function() {
$(".alert").fadeTo(500, 0).slideUp(500, function(){
$(this).remove();
});
}, 4000);

setTimeout(getResults, 500);
});
});
});
});

function getResults(){
var dataArr = [];
var backgroundColorArr = [];
var borderArr = [];
var labelsArr = [];
var colorArr = ['rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)'];

for(var i=0;i<candidateList.length;i++){
dataArr.push(0);
labelsArr.push(candidateList[i].firstName + " " + candidateList[i].lastName);
backgroundColorArr.push(colorArr[i%2]);
borderArr.push(colorArr[i%2]);
}

$.get("http://localhost:3000/api/Vote", function(data){
for(var i=0;i<data.length;i++){
for(var j=0;j<candidateList.length;j++){
if(data[i].candidate == 'resource:org.example.empty.Candidate#' + candidateList[j].firstName){
var count = dataArr[j] + 1;
dataArr[j] = count;
}
}
}
});

setTimeout(function(){
var ctx = document.getElementById("resultChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labelsArr,
datasets: [{
label: '# of Votes',
data: dataArr,
backgroundColor: backgroundColorArr,
borderColor: borderArr,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}, 500);

setTimeout(function(){$("#modalResult").modal("show");}, 700);
}
</script>

</body>
</html>

React 版本

根据官方网站,React是一个用于构建用户界面的JavaScript库。它是声明性的和基于组件的。它被用来开发网页,向Hyperledger Composer提供的REST服务器发出post和get请求。

结果如下所示。用户可以登录系统并选择他们想要的候选人。候选人选项卡中存在创建新候选人或删除现有候选人的信息。由于用户需要登录系统,因此如果用户未通过系统身份验证,则“候选人”和“投票”标签将重定向到“登录”屏幕。

在这个项目中,vote react目录是所有react代码和文件所在的位置,

此外,Hyperledger Composer还为开发环境提供了2个选择。

·第一个是在线商业环境。我们还可以在浏览器上建立和管理我们的业务网络,资产,参与者和交易。

· 第二个是针对Rest API的Angular 4应用程序。Hyperledger Composer可以在4200端口上显示现有的Web应用程序,就像我们在此应用程序中完成的应用程序一样。

内容来源:区块链研究实验室 作者:链三丰

版权声明:本文仅为传播消息之用,不代表币源社区立场,文章不构成投资建议。如需转载,请务必注明文章原作者以及来源,部分图片来源于网络,我们尊重版权,如有疑问敬请联系,我们将核实并删除。

我要评论
字数上限500
评论(0)