投票智能合约的编译和调用
2019-02-18 本文已影响32人
小朴同学
- 部署
部署参考只能合约的简单编程。 - 智能合约代码
// title 授权投票 contract Ballot { // 这里声明了复杂类型 // 将会在被后面的参数使用 // 代表一个独立的投票人。 struct Voter { uint weight; // 累积的权重,也就是具有的投票数 bool voted; // 如果为真,则表示该投票人已经投票。 address delegate; // 委托的投票代表(如果自己不投,委托给别人,这个别人的地址) uint vote; // 投票选择的提案索引号(投的提案) } // 这是一个独立提案的类型 struct Proposal { string name; // 提案的短名称 uint voteCount; // 提案累计获得的票数 } // 提案创建者地址 address public chairperson; // 这里声明一个状态变量,保存每个独立地址的`Voter` 结构 mapping(address => Voter) public voters; // 一个存储`Proposal`结构的动态数组 Proposal[] public proposals; // 提案名字数组 string[] public myProposalNames; // 创建一个新的投票用于选出一个提案名`proposalNames` // 这个构造函数,会在合约执行的第一次直接调用 function Ballot() public { // 提案创建者 chairperson = msg.sender; // 这个地址的投票数为1,只有一票 voters[chairperson].weight = 1; // 数组元素 myProposalNames = ['tom', 'david', 'Bob']; // 对提供的每一个提案名称,创建一个新的提案 // 对象添加到数组末尾 for (uint i = 0; i < myProposalNames.length; i++) // 添加到了提案数组`proposals`末尾 proposals.push( // 创建了一个临时的提案对象 Proposal({ name: myProposalNames[i], voteCount: 0 }) ); } // 给投票人`voter`参加投票的投票权, // 只能由投票主持人`chairperson`调用。 function giveRightToVote(address voter) { // 添加可以投票的人,这个人不可以是投票创建者,不能已经投过票 if (msg.sender != chairperson || voters[voter].voted) // `throw`会终止和撤销所有的状态和以太改变。 // 如果函数调用无效,这通常是一个好的选择。 // 但是需要注意,这会消耗提供的所有gas。 throw; // 这个新的可以投票的人,拥有一票 voters[voter].weight = 1; } // 委托你的投票权到一个投票代表,自己不投,权利给别人 function delegate(address to) { // 首先确定这个更改投票权的人,本身自投票人列表中 Voter sender = voters[msg.sender]; // 确定他是否已经投票 if (sender.voted) throw; // 当投票代表`to`也委托给别人时,寻找到最终的投票代表 while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender) to = voters[to].delegate; // 当最终投票代表等于调用者,是不被允许的。 if (to == msg.sender) throw; // 因为`sender`是一个引用, // 当你把投票权给别人时,你本身是已投票状态。 sender.voted = true; // 你的投票代理 sender.delegate = to; // 代理者 Voter delegate = voters[to]; // 如果你委托的投票者,已经投票 if (delegate.voted) // 那么你的票,直接累加在委托者投票的提案上 proposals[delegate.vote].voteCount += sender.weight; else // 如果投票代表还没有投票,则修改委托者拥有的投票数量。 delegate.weight += sender.weight; } // 投出你的选票(包括委托给你的选票) // 给 `proposals[proposal].name`。 function vote(uint proposal) { // 获得要投票的对象 Voter sender = voters[msg.sender]; // 判断是否投票 if (sender.voted) throw; // 修改为已投 sender.voted = true; // 记录投票者的选择 sender.vote = proposal; // 如果`proposal`索引超出了给定的提案数组范围 // 将会自动抛出异常,并撤销所有的改变。 proposals[proposal].voteCount += sender.weight; } // 根据当前所有的投票计算出当前的胜出提案 function winningProposal() constant 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; } } } }
- 调用
- 部署之后的立刻调用和之前没啥区别
- 部署之后其他节点的调用或者重新打开配置环境再次调用
// 部署之后的再次调用,需要记住abi abi = [{"constant":false,"inputs":[{"name":"proposal","type":"uint256"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"name","type":"string"},{"name":"voteCount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"chairperson","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"delegate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"winningProposal","outputs":[{"name":"winningProposal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"myProposalNames","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"voter","type":"address"}],"name":"giveRightToVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"voters","outputs":[{"name":"weight","type":"uint256"},{"name":"voted","type":"bool"},{"name":"delegate","type":"address"},{"name":"vote","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] // 需要记住部署成功后的Contract mined! address contractMinedAddress = '0xcd4dc04ce4452ed24d76b04a80fe4094b178dc22' // 获得bytecode // bytecode = eth.getCode(adress); // 合约 contract = web3.eth.contract(abi) // 合约实例对象 myContractInstance = contract.at(contractMinedAddress)
- 合约函数或者数组,变量的调用
1. 一个公开的变量可以如此 > myContractInstance.chairperson() "0x4079a3f5ffeeb7a84a4a582e9fc5f25579c3bba0" 2. 一个公开的数组 > myContractInstance.myProposalNames(0) "tom" // 不可以,需要后缀第几个元素,这个被eth.accounts误导,这个命令直接输出数组,而下面函数必须输入index > myContractInstance.myProposalNames() 3. 一个复杂的调用,即如果这个调用需要得到矿工去确认的 // 先解锁 > personal.unlockAccount(user,'abc123') // 然后如此调用投票给第一个元素即index为0的元素 > myContractInstance.vote.sendTransaction(0, {from:user, gas:4700000}) // 需要去挖矿,才能得到确认 > miner.start()