最近一直在学习BlockChain相关的知识,Ethereum网上也没有太好的资料,就先拿官网的一些example学习下吧。
本篇解析下使用智能合约编写的投票合约。
先看下代码,注释给的也比较清楚,虽然是一门新的语言,但读懂应该没有什么难度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| pragma solidity ^0.4.22;
contract Ballot { struct Voter { uint weight; bool voted; address delegate; uint vote; }
struct Proposal { bytes32 name; uint voteCount; }
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
constructor(bytes32[] proposalNames) public { chairperson = msg.sender; voters[chairperson].weight = 1; for (uint i = 0; i < proposalNames.length; i++) { proposals.push(Proposal({ name: proposalNames[i], voteCount: 0 })); } }
function giveRightToVote(address voter) public { require( msg.sender == chairperson, "Only chairperson can give right to vote." ); require( !voters[voter].voted, "The voter already voted." ); require(voters[voter].weight == 0); voters[voter].weight = 1; }
function delegate(address to) public { Voter storage sender = voters[msg.sender]; require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while (voters[to].delegate != address(0)) { to = voters[to].delegate; require(to != msg.sender, "Found loop in delegation."); }
sender.voted = true; sender.delegate = to; Voter storage delegate_ = voters[to]; if (delegate_.voted) { proposals[delegate_.vote].voteCount += sender.weight; } else { delegate_.weight += sender.weight; } }
function vote(uint proposal) public { Voter storage sender = voters[msg.sender]; require(!sender.voted, "Already voted."); sender.voted = true; sender.vote = proposal proposals[proposal].voteCount += sender.weight; }
function winningProposal() public view returns (uint winningProposal_) { uint winningVoteCount = 0; for (uint p = 0; p < proposals.length; p++) { if (proposals[p].voteCount > winningVoteCount) { winningVoteCount = proposals[p].voteCount; winningProposal_ = p; } } }
function winnerName() public view returns (bytes32 winnerName_) { winnerName_ = proposals[winningProposal()].name; } }
|
合约测试可以在Solidity IDE中测试,也可以在geth中执行,先来看个简单一点的,使用remix在线IDE进行合约部署。
Remix IDE运行合约
Remix IDE可以使用在线的,也可能本地安装。(在线的IDE有时会比较慢,我就安装了个本地的,结果发现本地的也比较慢,不知道是不是我虚拟机的问题。。。)
这里先使用在线版的,随后写个本地安装Remix的教程。
在Remix IDE的左上角有个”+”的图标,点击新建一个文件,将上述代码copy进去。
文件创建成功之后就是选择Solidity的版本,编译代码,如图:
编译成功之后就是部署合约,这里点击Deploy
之后会帮你将合约部署到以太坊的测试环境中,部署流程如图:
因为合约的构造函数需要输入参数,所以在deploy的时候,需要传入参数。
这里参数是一个bytes32的数组,在有的版本中string可以转成bytes32,但在0.4.22
中无法直接转,
所以这里我们要直接输入byte32的一个数组["0x616263", "0x646566", "0x676869"]
,
转化成字符串为["abc", "def", "ghi"]
合约部署好之后,就可以调用合约的一些方法了,比如vote和giveRightToVote
vote方法需要传入的参数是uint,是proposals
数组的索引,这里注意不要越界。
giveRightToVote方法传入的参数是address,意思是给某个地址授权,使其能够进行投票,
这个address可以在Account中选择(remix会默认创建5个账号),如图:
将选择好的address粘贴到参数栏中调用该方法给address授权,
然后依然在Account选项中切换到该address,就可以以该账号进行操作了,比如调用vote给某个提案投票。
其它的方法也可以尝试着调用下,加深对代码的理解。
这是用Remix IDE进行测试开发,还可以使用geth命令行模式进行开发测试,geth相对于Remix IDE就比较繁琐,具体流程下次再续。。。