文章目录
- 四、智能合约的开发和WeBASE合约IDE的使用
- 一、实验概述
- 二、实验目标
- 三、实验环境及建议
- 四、实验步骤
- 4.1 启动Webase
- 4.2 智能合约开发
- 4.2.1 合约功能设计
- 4.2.2 存证合约开发
- 4.2.3 工厂合约开发
- 4.3 合约功能验证
- 4.3.1 新建用户
- 4.3.2 部署合约
- 4.3.3 合约调用
四、智能合约的开发和WeBASE合约IDE的使用
一、实验概述
智能合约是管理区块链中账户行为的程序。FISCO BCOS平台目前支持Solidity及Precompiled两类合约形式。
Solidity合约与以太坊相同,用Solidity语法实现。Solidity是一门为实现智能合约而创建的面向对象的高级编程语言。
KVTable合约的读写接口与Table合约的CRUD接口通过在Solidity合约中支持分布式存储预编译合约,可以实现将Solidity合约中数据存储在FISCO BCOS平台AMDB的表结构中,实现合约逻辑与数据的分离。
预编译(Precompiled)合约使用C++开发,内置于FISCO BCOS平台,相比于Solidity合约具有更好的性能,其合约接口需要在编译时预先确定,适用于逻辑固定但需要共识的场景,例如群组配置。关于预编译合约的开发将在下一节进行介绍。
这里只介绍Solidity合约形式,关于solidity详细内容请参阅官方文档https://docs.soliditylang.org/zh/latest/index.html。
本实验将以具体的示例介绍智能合约的开发,进一步熟悉使用WeBASE合约IDE的进行合约代码的编辑、保存、编译、部署和调用等操作。
二、实验目标
- 了解Solidity合约的基础知识;
- 掌握Solidity智能合约的开发;
- 掌握WeBASE合约IDE的进行合约代码的编辑、保存、编译、部署和调用。
三、实验环境及建议
- 熟悉Solidity基本语法和编程技巧;
- 了解智能合约的运行机制等;
四、实验步骤
4.1 启动Webase
本实验将基于可视化WeBASE合约IDE完成智能合约的开发、部署和调用等操作。
首先,切换到Webase目录下,启动Webase IDE;
cd ~/fisco/webase-deploy/ && python3 deploy.py startAll
打开桌面浏览器,在地址栏输入地址http://127.0.0.1:5000访问webase平台,也可以使用物理机访问webase平台。
输入初始账户/密码:admin/你自己设置的,并根据提示输入验证码;
4.2 智能合约开发
4.2.1 合约功能设计
本实验要实现一套区块链存证合约Evidence,主要功能有创建/添加存证,添加签名和取证等。使用分层的智能合约结构:
1)工厂合约(EvidenceSignersData.sol),由存证各方事前约定,存储存证生效条件,并管理存证的生成。
2)存证合约(Evidence.sol),由工厂合约生成,存储存证id,hash和各方签名(每张存证一个合约)。
按照以上设计,需要在工厂合约中实现的函数接口功能有:
newEvidence(string evi)public returns(address):创建新签证事件,返回地址
verify(address addr)public constant returns(bool):验证身份是否为合法签名者地址
getEvidence(address addr) public constant returns(string,address[],address[]):获取存证信息
addSignatures(address addr) public returns(bool):添加合法签名者
getSigner(uint index)public constant returns(address):返回签名者地址
getSignersSize() public constant returns(uint):获取总签名人数
getSigners() public constant returns(address[]):返回所有合约签名者的地址
4.2.2 存证合约开发
点击左侧导航栏【合约管理】,展开后点击【合约IDE】,进入合约编辑页面,点击新建智能合约按钮;
输入合约名称’Evidence’(不用添加.sol后缀名),文件目录选择根目录’/’,也可自己创建目录后选择自己创建的目录;
在代码编辑区域写入代码。为保证代码符合软件工程规范,并提高代码可读性,在编写代码时,添加适当的代码注释是必要的。
(1)声明版本solidity版本,目前Webase IDE支持0.4.25、0.5.2和0.6.10三个版本。
pragma solidity ^0.4.25;
(2)设置合约ABI接口,主要声明verify()
函数、getSigner()
函数、getSignersSize()
函数。
contract EvidenceSignersDataABI{//验证是否是合法地址function verify(address addr)public constant returns(bool){}//根据索引值返回签名者地址function getSigner(uint index)public constant returns(address){}//返回签名人数function getSignersSize() public constant returns(uint){}}
(3)定义存证合约主体,具体实现过程和代码功能请参考代码中的注释。
注意:此处定义的合约名要和合约文件名保持一致,否则会报错!!
contract Evidence{string evidence; //存证信息address[] signers;//储存合法签名者地址address public factoryAddr;//工厂合约地址//返回事件信息,查看log->判断正确或错误的信息event addSignaturesEvent(string evi);event newSignaturesEvent(string evi, address addr);event errorNewSignaturesEvent(string evi, address addr);event errorAddSignaturesEvent(string evi,address addr);event addRepeatSignaturesEvent(string evi);event errorRepeatSignaturesEvent(string evi, address addr);//查看此地址是否为合法签名者地址function CallVerify(address addr) public constant returns(bool){return EvidenceSignersDataABI(factoryAddr).verify(addr);}//初始化,创建存证合约constructor(string evi, address addr){factoryAddr = addr;//tx.origin =>启动交易的原始地址(其实就是部署者的地址)//如果是外部调用,在此可以理解为函数调用者地址if(CallVerify(tx.origin)) {evidence = evi;signers.push(tx.origin);newSignaturesEvent(evi,addr); }else {errorNewSignaturesEvent(evi,addr);}}//返回签名信息,合约签名者地址,当前签名者地址function getEvidence() public constant returns(string,address[],address[]){uint length = EvidenceSignersDataABI(factoryAddr).getSignersSize();address[] memory signerList = new address[](length);for(uint i=0 ;i<length ;i++) {signerList[i] = (EvidenceSignersDataABI(factoryAddr).getSigner(i));}return(evidence,signerList,signers);}//添加签名者地址(此地址必须为合约签名者地址)function addSignatures() public returns(bool) {for(uint i=0 ;i<signers.length ;i++){//此时的tx.orgin为当前调用此方法的调用者地址if(tx.origin == signers[i]){addRepeatSignaturesEvent(evidence);return true;}}if(CallVerify(tx.origin)) {signers.push(tx.origin);addSignaturesEvent(evidence);return true; }else {errorAddSignaturesEvent(evidence,tx.origin);return false;}}//返回所有的合约签名者地址function getSigners()public constant returns(address[]) {uint length = EvidenceSignersDataABI(factoryAddr).getSignersSize();address[] memory signerList = new address[](length);for(uint i=0 ;i<length ;i++){signerList[i] = (EvidenceSignersDataABI(factoryAddr).getSigner(i));}return signerList;}}
代码编辑完成后,点击右上角【保存】按钮,保存合约。
然后点击右上角【编译】按钮,进行合约的编译,确保合约无语法错误。
4.2.3 工厂合约开发
按照步骤4.2.2中方法,在同一目录下新建工厂合约EvidenceSignersData
;
然后按合约设计内容,编写合约代码。
(1)声明solidity版本,并导入步骤4.2.2中存证合约Evidence.sol
;
pragma solidity ^0.4.25;import "Evidence.sol";
(2)完成EvidenceSignersData
合约主要内容,具体实现过程和代码功能请参考代码中的注释。
contract EvidenceSignersData{address[] signers;//存储签名者地址event newEvidenceEvent(address addr); //新签证事件,返回地址//传入签名内容 string类型,创建合约Evidence并初始化function newEvidence(string evi)public returns(address){//this:代表当前工厂合约的地址Evidence evidence = new Evidence(evi, this);newEvidenceEvent(evidence);return evidence;}//获得签证信息function getEvidence(address addr) public constant returns(string,address[],address[]){return Evidence(addr).getEvidence();}function addSignatures(address addr) public returns(bool) {return Evidence(addr).addSignatures(); }//初始化合约,导入签名者们的地址(数组传参)为合法签名者地址//只有合法签名者才有资格进行签证constructor(address[] evidenceSigners){for(uint i=0; i<evidenceSigners.length; ++i) {signers.push(evidenceSigners[i]);}}// 验证身份是否为合法签名者地址function verify(address addr)public constant returns(bool){for(uint i=0; i<signers.length; ++i) {if (addr == signers[i]){return true;}}return false;}//根据索引值返回合约签名者地址function getSigner(uint index)public constant returns(address){uint listSize = signers.length;//判断索引值是否越界if(index < listSize){return signers[index];}else{return 0;}}//获取当前合约签名者人数function getSignersSize() public constant returns(uint){return signers.length;}//返回所有合约签名者的地址function getSigners() public constant returns(address[]){return signers;}}
代码编辑完成后,点击右上角【保存】按钮,保存合约。
然后点击右上角【编译】按钮,进行合约的编译,确保合约无语法错误。
4.3 合约功能验证
合约编译通过后,经过部署和调用2个步骤,验证合约功能是否正确。
4.3.1 新建用户
部署合约前需要用户地址,所以先要创建账户。点击左侧【私钥管理】->【新增用户】,根据实际情况输入用户名【chain01】和用户描述(选填)。
点击【确定】后,新建用户出现在列表中;
因存证合约中的【签名】功能至少由2个用户完成,所以按同样方法,新建用户【chain02】。
将2个用户的地址信息复制保存到文本数组中备用,如
[“0xe2e2ec75dc8f15a7d417d4450cd0f194bf321a50”,
“0xd0ee8d1abe3cd3ce5b7547753997efaffe543320”],根据实际情况复制。
4.3.2 部署合约
切换到合约管理下,在工厂合约EvidenceSignersData
页面下,点击右上角【部署】按钮,将合约部署到链上。
然后选择用户并进行初始化,如下图所示,其中:
用户:下拉框选择上述步骤中创建的【chain01】用户;
参数
evidenceSigners
:填入上述步骤中保存的2个用户的地址数组[“0xe2e2ec75dc8f15a7d417d4450cd0f194bf321a50”,
“0xd0ee8d1abe3cd3ce5b7547753997efaffe543320”]完成初始化,这2个地址作为合法的签名地址,所有的存证都要经过这两个用户签名方可;
点击【确定】,提示合约部署成功!
4.3.3 合约调用
点击右上角【发交易】按钮,验证合约功能函数。
(1) verify()合法签名者地址验证
在弹出的窗口中选择function为【verify】,addr栏输入【chain02】用户地址,如图所示;
按照前面步骤,因为用户【chain02】是合法签名者,所以此时交易回执返回true。
(2) getSigners查看合法签名者地址
再次点击右上角【发交易】,在弹出的窗口中选择function为【getSigners】,查看合法签名者地址,如图所示;
点击【确定】,返回所有合法签名者的地址,如图所示,返回的是【chain01】和【chain02】的地址,与前面步骤设置一致。
(3)创建签证合约(只有合法签名者才能成功创建)
再次点击右上角【发交易】,在弹出的窗口中选择function为【newEvidence】,创建一个签证,用户选择【chain02】,参数输入自定义内容,如【4C大赛区块链开发与应用】,如图所示;
点击【确定】,返回交易回执,信息较多,下拉滚动条,可以查看到新建合约的事件newSignaturesEvent
,如图所示,
继续下拉,可查看签证地址,点击图标可保存签证地址,便于后续操作查询签证内容。
(4)查看签证信息
再次点击右上角【发交易】,在弹出的窗口中选择function为【getEvidence】,查看签证信息,参数输入上述步骤中保存的签证地址,如图所示;
注意:如上述步骤中未保存签证地址,可依次点击【数据概览】->【交易数量】,找到最近一次交易展开,【交易回执】中查看!
点击【确定】,返回交易回执,得到签证内容,以及合法签名者地址和当前签名者地址信息。
(5)新增签名
上述步骤完成了其中一个用户对存证的签名,还要继续新增另一个用户对存证的签名,才能生效。
再次点击右上角【发交易】,在弹出的窗口中选择function为【addSignatures】,因创建存证时选择的是用户chain02,所以此处用户选择chain01,然后新增签名,参数addr输入前述保存的存证的地址,如图所示;
点击确定,返回交易回执!
再次点击右上角【发交易】,在弹出的窗口中选择function为【getEvidence】,再次查看签证信息。
点击确定,返回交易回执!此时显示2个合法签名者全部完成签名。
至此,我们完成了存证合约的设计和实现,并使用Webase IDE完成了合约代码的编辑、保存、编译、部署和发交易等各个环节!