实验1 会议报名登记系统的基本功能与实现
实验流程
系统功能要求:
合约参与方包含一个管理员以及其余参与者,管理员可以发起不止一个会议,并指定会议信息以及总人数。
参与者首先需要进行注册,将个人基本信息与以太坊地址相关联,并存储在合约上。
之后可进行报名,或委托他人为自己报名。
当会议报名人满时,该会议将不再可报名。
当合约内某些数据发生变化时,应能够触发事件(event)使前端重新获取并渲染数据,例如当某个会议报名人满时,应触发相应事件使前端及时更新可报名会议列表。
按功能要求与模板文件补全代码中的委托函数及为受托者报名函数。
在 delegate
函数中建立受托人到其委托人的一个映射,然后在enrollFor
函数中实现受托人为委托人报名功能,首先由username
找到受托人,后续报名流程仿写enroll
,更换报名对象即可,该部分代码如下:
function delegate(address addr) public{ trustees[addr].push(participants[msg.sender]); } function enrollFor(string memory username,string memory title) public returns(string memory){ uint index = 0; for (uint i = 0; i < trustees[msg.sender].length; i++) { if (keccak256(bytes(trustees[msg.sender][i].name)) == keccak256(bytes(username))) { index = i; break; } } for (uint i = 0; i < conferences.length; i++){ if (keccak256(bytes(conferences[i].title)) == keccak256(bytes(title))){ require(conferences[i].current<conferences[i].max,"Enrolled full"); conferences[i].current = conferences[i].current+1; if(conferences[i].current==conferences[i].max){ emit ConferenceExpire(title); } trustees[msg.sender][index].confs.push(title); } } uint len = trustees[msg.sender][index].confs.length; require(len>0,"Conference does not exist"); return trustees[msg.sender][index].confs[len-1]; }
练习1
应在合约的哪个函数指定管理员身份?如何指定?
在合约的构造函数中指定,用address public admin
指定admin为管理员
在发起新会议时,如何确定发起者是否为管理员?简述require()、assert()、revert()的区别。
判别语句:require(msg.sender==admin,"permission denied");
如下三个语句与if(msg.sender != owner) { throw; }
效果等价
if(msg.sender != owner) { revert(); } assert(msg.sender == owner); require(msg.sender == owner);
revert()
处理与require()
同样的类型,但是需要更复杂处理逻辑的场景,二者都会将剩余gas费返还给调用者,而assert()
不返还gas费,所以一般很少用assert()
简述合约中用memory和storage声明变量的区别。
Storage
变量是指永久存储在区块链中的变量。Memory
变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。
状态变量(在函数之外声明的变量)默认为storage
形式,并永久写入区块链;而在函数内部声明的变量默认是memory
型的,它们函数调用结束后消失。
实验2 学习用Truffle组件部署和测试合约
安装Truffle和Ganache
按照教程按照即可
为合约编写测试文件
pragma solidity >=0.4.25 <0.7.0; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Enrollment.sol"; contract TestEnrollment{ //测试注册后,是否返回正确注册信息(仅测试name即可) function testSignUp() public { Enrollment en = new Enrollment(); (string memory name,) = en.signUp("alice","male"); (string memory expected_name,) = ("alice","male"); Assert.equal(name,expected_name,"signup failed"); } //测试管理员添加新会议是否成功 function testNewConf() public{ Enrollment enroll = new Enrollment(); string memory expected = "conf1"; Assert.equal(enroll.newConference("conf1","beijing",30),expected,"new conference failed"); } //请测试enroll函数,确保当用户报名后,其已报名会议列表中有该会议。提示:不要忘记先由管理员创建会议。 function testEnroll() public{ Enrollment en = new Enrollment(); string memory expected="conf1"; en.newConference("conf1","beijing",30); Assert.equal(en.enroll("conf1"),expected,"Enrolled full"); } }
进行测试truffle test
用Ganache搭建私链
测试后重新搭建一条私链
进行合约部署truffle migrate
,成功部署
合约部署后的记录
合约部署的主要流程包括以下4个步骤:
(1)启动一个以太坊节点
(2)编写智能合约
(3)编写后的智能合约经以太坊虚拟机的编译,成为计算机可运行的字节码
(4)合约发起用户将编译好的字节码文件通过发起交易的形式广播到区块链网络中,由矿工挖矿确认后即可将智能合约存入区块链中,并得到智能合约所在地址及调用合约所需接口
在节点触发智能合约条件需要使用合约时,区块链将调取智能合约字节码在本地运行,然后将运行结果再保存入区块链账本中。
另外,用户还可以通过web3接口调用智能合约,构建与之交互的Web应用,该应用由于完全构建于区块链之上,不需要第三方中介来提供服务,被称为去中心化应用(DAPP)。
实验3 利用Web3.js实现合约与前端的结合
首先按照指导书配置Metamask
在前端项目文件中配置合约信息
配置src/contracts/contract.js
中的abi和合约地址
完成组件代码中交互代码
仿照SignUp完成其他组件的交互代码
delegate
submit(address) { //调用合约 contract.methods.delegate(address) .send({from:window.web3.eth.accounts[0]},function(err,res){console.log(res)}) //function中的res为方法返回值 .then((res)=>console.log(res)); //该res为交易执行完后的具体交易信息,如TxHash等
enrollFor
submit(username,title) { //在此调用合约 contract.methods.enrollFor(username,title) //输入参数 .send({from:window.web3.eth.accounts[0]},function(err,res){console.log(res)}) //function中的res为方法返回值 .then(); //该res为交易执行完后的具体交易信息,如TxHash等
myConf
componentDidMount(){ //学习conflist/index.js该位置代码进行实现。 contract.methods.queryMyConf() .call({from:window.web3.eth.accounts[0]},(err,res)=>{ //将返回的数组依次压入data中 this.setState({loading: true}); if(res != null){ for(var i=0;i<res.length;i=i+1){ data.push({'title': res[i]}); } } else{ data.push({'title': 'no'}); } }) .then(()=>{ //更新状态,使页面数据重新渲染 this.setState({loading: false}); }); }
运行效果
npm install
和npm start
后,前端出现:
绑定两个账户
注册用户
报名会议并支付花费后
为usr2报名会议
上课检查时候似乎是myconf写的有问题。。前端刷新不出来
Author:
紫炁
License:
Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan:
Do you believe in DESTINY ?