区块链应用开发(智能合约的开发和WeBASE合约IDE的使用)

四、智能合约的开发和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的进行合约代码的编辑、保存、编译、部署和调用等操作。

二、实验目标

  1. 了解Solidity合约的基础知识;
  2. 掌握Solidity智能合约的开发;
  3. 掌握WeBASE合约IDE的进行合约代码的编辑、保存、编译、部署和调用。

三、实验环境及建议

  1. 熟悉Solidity基本语法和编程技巧;
  2. 了解智能合约的运行机制等;

四、实验步骤

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完成了合约代码的编辑、保存、编译、部署和发交易等各个环节!

猜你喜欢

转载自blog.csdn.net/m0_46635662/article/details/130133561
今日推荐