预计阅读时间24分钟
Solidity数组,所以这里我们需要使用一个变通的方案。
用一个变量保存一共有多少个候选人uint public candidatesCount
,然后定义一个映射:
mapping(uint => Candidate) public candidates
通过id作为key
访问映射candidates来取候选人。
投票功能实现
接下来就是添加功能: 主要是两个功能: 添加候选人及投票。
每添加一个候选人就加入到candidates映射中,同时候选人数量加1,添加候选人addCandidate函数实现为:
function addCandidate (string memory _name) private {
candidatesCount ++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
我们在合约创建的时候,就把候选人添加好,在构造函数中,调用addCandidate,构造函数实现如下:
constructor () public {
addCandidate("Tiny 熊");
addCandidate("Big 熊");
}
投票就是在对应的候选人的voteCount加1,同时这个函数需要一个参数即给哪一个候选人投票,另外需要进行一些合法性检查: 候选人是有效的,投票人必须没有投过票,投票vote函数实现如下:
function vote (uint _candidateId) public {
require(!voters[msg.sender]);
require(_candidateId > 0 && _candidateId <= candidatesCount);
voters[msg.sender] = true;
candidates[_candidateId].voteCount ++;
}
事件Event
为了有更好的前端体验, 在用户投票之后,应该及时的刷新页面, 这就需要用到事件了。
你还可以阅读另外一篇文章:详解 Solidity 事件Event 了解更多事件知识。
先定义一个事件:
// voted event
event votedEvent (
uint indexed _candidateId
);
然后在投票vote函数中最后一行加入发出事件:
emit votedEvent(_candidateId);
合约部分代码编写完了, 订阅小专栏 获取完整源代码。
合约部署
为合约Election,添加一个部署脚本:
var Election = artifacts.require("./Election.sol");
module.exports = function(deployer) {
deployer.deploy(Election);
};
在部署之前,还需要打开以太坊的模拟节点Ganache,并确保Truffle配置文件truffle.js 链接节点的地址和端口与Ganache 一致。
Ganache 的安装使用可阅读开发、部署第一个DApp
如果要部署到以太坊正式网络可阅读用Truffle 开发一个链上记事本
然后运行一下命令进行部署:
truffle migrate
前端界面
有一个html table
标签显示候选人列表:
```html
投票最担心的是暗箱操作、利用区块链的去中心化技术,来实现一个DAPP保证投票公平公正,来看看如何实现,通过本文可以了解到映射mapping
、结构体struct
及事件 event
的使用。
投票需求分及实现效果
要实现一个投票DApp,对于合约来说有两个基本需求:
- 每人(账号)只能投一票;
- 记录下一共有多少候选人
- 记录每个候选人的得票数。
在界面上,需要看到每个候选人的得票数, 已经选择投票人进行投票,来看看实现的效果图:
投票界面及结果
投票合约实现
数据存储
每人(账号)只能投一票很容易实现,只需要使用一个mapping
来记录每个地址的投票信息
定义一个 mapping 记录投票记录:
mapping(address => bool) public voters;
记录候选人及得票数, 我们思考下,如何合约中表示一个候选人,这里我们用一个结构体来表示候选人:
struct Candidate {
uint id;
string name; // 候选人的名字
uint voteCount;
}
在Candidate结构体中,用voteCount
表示得票数。我们还需要记录下一共有多少个候选人,直觉是保存到一个数组,前端需要候选人列表时,直接把这个数组返回给前端。
基于EVM的限制,外部函数是没法返回动态的内容,更多可阅读Solidity数组,所以这里我们需要使用一个变通的方案。
用一个变量保存一共有多少个候选人uint public candidatesCount
,然后定义一个映射:
mapping(uint => Candidate) public candidates
通过id作为key
访问映射candidates来取候选人。
投票功能实现
接下来就是添加功能: 主要是两个功能: 添加候选人及投票。
每添加一个候选人就加入到candidates映射中,同时候选人数量加1,添加候选人addCandidate函数实现为:
function addCandidate (string memory _name) private {
candidatesCount ++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
我们在合约创建的时候,就把候选人添加好,在构造函数中,调用addCandidate,构造函数实现如下:
constructor () public {
addCandidate("Tiny 熊");
addCandidate("Big 熊");
}
投票就是在对应的候选人的voteCount加1,同时这个函数需要一个参数即给哪一个候选人投票,另外需要进行一些合法性检查: 候选人是有效的,投票人必须没有投过票,投票vote函数实现如下:
function vote (uint _candidateId) public {
require(!voters[msg.sender]);
require(_candidateId > 0 && _candidateId <= candidatesCount);
voters[msg.sender] = true;
candidates[_candidateId].voteCount ++;
}
事件Event
为了有更好的前端体验, 在用户投票之后,应该及时的刷新页面, 这就需要用到事件了。
你还可以阅读另外一篇文章:详解 Solidity 事件Event 了解更多事件知识。
先定义一个事件:
// voted event
event votedEvent (
uint indexed _candidateId
);
然后在投票vote函数中最后一行加入发出事件:
emit votedEvent(_candidateId);
合约部分代码编写完了, 订阅小专栏 获取完整源代码。
合约部署
为合约Election,添加一个部署脚本:
var Election = artifacts.require("./Election.sol");
module.exports = function(deployer) {
deployer.deploy(Election);
};
在部署之前,还需要打开以太坊的模拟节点Ganache,并确保Truffle配置文件truffle.js 链接节点的地址和端口与Ganache 一致。
Ganache 的安装使用可阅读开发、部署第一个DApp
如果要部署到以太坊正式网络可阅读用Truffle 开发一个链上记事本
然后运行一下命令进行部署:
truffle migrate
前端界面
有一个html table
标签显示候选人列表:
```html
投票最担心的是暗箱操作、利用区块链的去中心化技术,来实现一个DAPP保证投票公平公正,来看看如何实现,通过本文可以了解到映射mapping
、结构体struct
及事件 event
的使用。
投票需求分及实现效果
要实现一个投票DApp,对于合约来说有两个基本需求:
- 每人(账号)只能投一票;
- 记录下一共有多少候选人
- 记录每个候选人的得票数。
在界面上,需要看到每个候选人的得票数, 已经选择投票人进行投票,来看看实现的效果图:
投票界面及结果
投票合约实现
数据存储
每人(账号)只能投一票很容易实现,只需要使用一个mapping
来记录每个地址的投票信息
定义一个 mapping 记录投票记录:
mapping(address => bool) public voters;
记录候选人及得票数, 我们思考下,如何合约中表示一个候选人,这里我们用一个结构体来表示候选人:
struct Candidate {
uint id;
string name; // 候选人的名字
uint voteCount;
}
在Candidate结构体中,用voteCount
表示得票数。我们还需要记录下一共有多少个候选人,直觉是保存到一个数组,前端需要候选人列表时,直接把这个数组返回给前端。
基于EVM的限制,外部函数是没法返回动态的内容,更多可阅读Solidity数组,所以这里我们需要使用一个变通的方案。
用一个变量保存一共有多少个候选人uint public candidatesCount
,然后定义一个映射:
mapping(uint => Candidate) public candidates
通过id作为key
访问映射candidates来取候选人。
投票功能实现
接下来就是添加功能: 主要是两个功能: 添加候选人及投票。
每添加一个候选人就加入到candidates映射中,同时候选人数量加1,添加候选人addCandidate函数实现为:
function addCandidate (string memory _name) private {
candidatesCount ++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
我们在合约创建的时候,就把候选人添加好,在构造函数中,调用addCandidate,构造函数实现如下:
constructor () public {
addCandidate("Tiny 熊");
addCandidate("Big 熊");
}
投票就是在对应的候选人的voteCount加1,同时这个函数需要一个参数即给哪一个候选人投票,另外需要进行一些合法性检查: 候选人是有效的,投票人必须没有投过票,投票vote函数实现如下:
function vote (uint _candidateId) public {
require(!voters[msg.sender]);
require(_candidateId > 0 && _candidateId <= candidatesCount);
voters[msg.sender] = true;
candidates[_candidateId].voteCount ++;
}
事件Event
为了有更好的前端体验, 在用户投票之后,应该及时的刷新页面, 这就需要用到事件了。
你还可以阅读另外一篇文章:详解 Solidity 事件Event 了解更多事件知识。
先定义一个事件:
// voted event
event votedEvent (
uint indexed _candidateId
);
然后在投票vote函数中最后一行加入发出事件:
emit votedEvent(_candidateId);
合约部分代码编写完了, 订阅小专栏 获取完整源代码。
合约部署
为合约Election,添加一个部署脚本:
var Election = artifacts.require("./Election.sol");
module.exports = function(deployer) {
deployer.deploy(Election);
};
在部署之前,还需要打开以太坊的模拟节点Ganache,并确保Truffle配置文件truffle.js 链接节点的地址和端口与Ganache 一致。
Ganache 的安装使用可阅读开发、部署第一个DApp
如果要部署到以太坊正式网络可阅读用Truffle 开发一个链上记事本
然后运行一下命令进行部署:
truffle migrate
前端界面
有一个html table
标签显示候选人列表:
```html