智能合约vote部署
1 前言
solidity官方文档上有一个vote智能合约。我使用truffle框架进行编写和部署。
2 环境
2.1 编辑
vscode + 插件
2.2 安装node
到官网下载node 8,解压后安装,配置环境变量。
2.3 solidity编译器
npm install -g solc
2.4 truffle安装
npm install -g truffle
2.5 ethereum安装
从https://github.com/ethereum/go-ethereum下载编译,配置环境。
3 ethereum私有链搭建
3.1 创建目录
/home/hlf/eth/data/00
3.2 genesis.json
/home/hlf/eth/genesis.json
{
"config": {
"chainId": 168, //不要为0
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" :"0x0000000000000000000000000000000000000000",
"difficulty" : "0x400",
"extraData" :"",
"gasLimit" :"0x2fefd8",
"nonce" :"0x0000000000000042",
"mixhash" :"0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" :"0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" :"0x00"
}
3.3 初始化脚本
/home/hlf/eth/init.sh
geth --datadir /home/hlf/eth/data/00 init/home/hlf/eth/genesis.json
3.4 start脚本
geth --identity "TestNode" --rpc--rpcport "8545" --datadir /home/hlf/eth/data/00--port "30303" --rpcapi "db,eth,net,web3" --networkid 168 --nodiscover console
4 truffle编写智能合约
4.1 创建目录
mkdir ~/vote
4.2 初始化框架
cd ~/vote
truffer init
创建目录结构如下:
4.3 编写智能合约
在contracts目录下添加文件vote.sol,使用vscode打开并编辑,内容如下,与官网一致:
pragma solidity ^0.4.22;
contract Ballot {
struct Voter { //a single voter.
uint weight; //weight isaccumulated by delegation
bool voted; //if true, that peson already voted
address delegate; //person delegated to 委托人
uint vote; //index of thevoted proposal
}
struct Proposal { //a singleproposal提议
bytes32 name; //short name (up to32 bytes)
uint voteCount; //number of accumulated votes
}
address public chairperson;
/*this declares a state variable that stores a 'voter'
struct for each possible address.
*/
mapping(address=> Voter) public voters;
//a dynamically-sized array of 'proposal' structs.
Proposal[] public proposals;
//Create a new ballot to choose one of 'proposalNames'
function Ballot(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
}));
}
}
//Give 'voter' the right to vote on this ballot.May only be called
//by `chairperson`
function giveRightToVote (address voter) public {
/*if the frist argument of 'require' evaluates to false,
execution terminates and changes to the state and ether balances arereveerted
this used to consume all gas in old EVM versions, but not anymore.
it is often a good idea to use 'require' to check if funcations arecalled
correctly.
as a second argument, you can also provide an exaplannation about waht
went wrong */
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"the voter already vote."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
//delegate委托 your vote to the voter 'to'
//msg.sender --表示执行该命令的账户
function delegate(address to) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You alreadyvoted.");
require(to != msg.sender, "Self-delegation is disabllowed.");
/*forward the delegation as long as to also delegated.
in general, such loops are very dangerous, because if they run too long,the
might need more gas than is available in a block.
in this case, the delegation will not be executed, but in othersituations,
such loops might cause a contract to get 'stuck' completely, */
//if to 委托给了别人,就向前委托
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;
}
}
4.4 启动eth,创建4个账户。
eth.accounts
personal.newAccount(“123456”) //该命令执行四次,创建四个账户
miner.start() -- 挖矿获得gas
4.5 配置部署环境
在truffle.js中添加
module.exports = {
//See <http://truffleframework.com/docs/advanced/configuration>
//to customize your Truffle configuration!
networks:{
live:{
host:"localhost",
port:8545,
network_id:"168",
from:"0x9cf2746d81814730281a72b74e6a84d5f627a78b",//账户[0]
gas:3000000
}
}
};
4.6 编写部署脚本
在migrations目录添加
var Ballot =artifacts.require("Ballot")
module.exports = function(deployer){
deployer.deploy(Ballot,["0x9cf2746d81814730281a72b74e6a84d5f627a78b","0x4b2f38a14e6337ef1ac15d1bd56e7ca68b1d181a","0xa06eb7296a0e8eec916eed082b82994b73e3186a", "0xc594cc30c42d92ba668f81f119c994b7f1c8ce88","0x57ef6050eec6bd838744b8b7592387d1489c56ea","0xabc2b333b13135e2fdfdc0d59b9f08de9a98298b"]);
}
4.7 部署过程
1) 解锁账户
2) 在另一个界面中truffle migrations--network live
5 在truffle console 执行智能合约
truffle console --network live
使用Ballot.deployed()查看
更详细的:1)实例化contract
Ballot.deployed().then(instance=>contract=instance)
2)调用函数:contract.winnerName()
在eth console中执行智能合约同普通的智能合约,通过abi创建合同,abi在vote/build目录中。该目录在truffle build后创建