您好,登录后才能下订单哦!
# 怎么用Node.js和truffle框架搭建区块链投票系统!

本文将手把手教你使用Node.js和Truffle框架构建一个去中心化的区块链投票系统,涵盖智能合约开发、前端交互和系统部署全流程。
## 一、项目概述与技术选型
### 1.1 为什么需要区块链投票系统?
传统电子投票系统存在中心化操控风险,而区块链技术的以下特性完美匹配投票场景:
- **不可篡改性**:投票记录一旦上链无法修改
- **透明可审计**:所有交易公开可查
- **去中心化**:无需信任单一机构
- **身份验证**:通过加密确保一人一票
### 1.2 技术栈组成
| 组件 | 技术选型 | 作用 |
|-------|---------|------|
| 区块链 | Ethereum | 底层分布式账本 |
| 开发框架 | Truffle Suite | 智能合约开发工具包 |
| 前端 | Node.js + Web3.js | DApp交互层 |
| 测试链 | Ganache | 本地开发环境 |
## 二、环境准备与项目初始化
### 2.1 安装必备工具
```bash
# 安装Node.js(建议v16+)
nvm install 16
# 安装Truffle和Ganache
npm install -g truffle
npm install -g ganache
# 验证安装
truffle version
ganache --version
mkdir voting-system && cd voting-system
truffle init
生成的项目结构:
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
├── truffle-config.js
└── package.json
在contracts/Voting.sol
中编写:
pragma solidity ^0.8.0;
contract Voting {
struct Candidate {
uint id;
string name;
uint voteCount;
}
mapping(uint => Candidate) public candidates;
uint public candidatesCount;
mapping(address => bool) public voters;
event votedEvent(uint indexed _candidateId);
constructor() {
addCandidate("候选人A");
addCandidate("候选人B");
}
function addCandidate(string memory _name) private {
candidatesCount++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
function vote(uint _candidateId) public {
require(!voters[msg.sender], "您已经投过票了");
require(_candidateId > 0 && _candidateId <= candidatesCount, "无效的候选人ID");
voters[msg.sender] = true;
candidates[_candidateId].voteCount++;
emit votedEvent(_candidateId);
}
}
在test/voting_test.js
中添加:
const Voting = artifacts.require("Voting");
contract("Voting", accounts => {
let votingInstance;
before(async () => {
votingInstance = await Voting.deployed();
});
it("初始化两个候选人", async () => {
const count = await votingInstance.candidatesCount();
assert.equal(count, 2);
});
it("允许投票", async () => {
await votingInstance.vote(1, { from: accounts[0] });
const candidate = await votingInstance.candidates(1);
assert.equal(candidate.voteCount, 1, "票数增加");
});
});
修改truffle-config.js
:
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545, // Ganache默认端口
network_id: "*"
}
},
compilers: {
solc: {
version: "0.8.0"
}
}
};
ganache
truffle migrate --reset
npm init -y
npm install express web3
创建app.js
:
const express = require('express');
const Web3 = require('web3');
const app = express();
const web3 = new Web3('http://localhost:7545');
// 合约ABI和地址
const contractABI = [...]; // 从build/contracts/Voting.json获取
const contractAddress = '0x...'; // 部署后获取
app.use(express.json());
// 前端路由
app.get('/candidates', async (req, res) => {
const contract = new web3.eth.Contract(contractABI, contractAddress);
const count = await contract.methods.candidatesCount().call();
let candidates = [];
for(let i = 1; i <= count; i++) {
const candidate = await contract.methods.candidates(i).call();
candidates.push(candidate);
}
res.json(candidates);
});
app.listen(3000, () => console.log('Server running on port 3000'));
创建public/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>区块链投票系统</title>
<script src="https://cdn.jsdelivr.net/npm/web3@1.5.2/dist/web3.min.js"></script>
</head>
<body>
<div id="app">
<h1>候选人列表</h1>
<ul id="candidates"></ul>
<button onclick="vote(1)">投票给候选人A</button>
<button onclick="vote(2)">投票给候选人B</button>
</div>
<script>
let votingContract;
window.addEventListener('load', async () => {
if(window.ethereum) {
window.web3 = new Web3(ethereum);
try {
await ethereum.enable();
initContract();
} catch(error) {
alert("用户拒绝访问账户");
}
}
});
function initContract() {
const contractABI = [...];
const contractAddress = '0x...';
votingContract = new web3.eth.Contract(contractABI, contractAddress);
loadCandidates();
}
async function loadCandidates() {
const count = await votingContract.methods.candidatesCount().call();
const ul = document.getElementById('candidates');
for(let i = 1; i <= count; i++) {
const candidate = await votingContract.methods.candidates(i).call();
ul.innerHTML += `<li>${candidate.name}: ${candidate.voteCount}票</li>`;
}
}
async function vote(candidateId) {
const accounts = await web3.eth.getAccounts();
await votingContract.methods.vote(candidateId).send({ from: accounts[0] });
alert("投票成功!");
location.reload();
}
</script>
</body>
</html>
modifier noReentrant() { require(!locked, “No re-entrancy”); locked = true; _; locked = false; }
2. **权限控制**:
```solidity
address public admin;
modifier onlyAdmin() {
require(msg.sender == admin, "Only admin");
_;
}
function addCandidate(string memory _name) public onlyAdmin {
require(bytes(_name).length > 0, "Name cannot be empty");
// ...
}
truffle-config.js
:
“`javascript
const infuraKey = “your-infura-key”;networks: {
ropsten: {
provider: () => new HDWalletProvider(
mnemonic,
https://ropsten.infura.io/v3/${infuraKey}
),
network_id: 3
}
}
### 7.2 执行部署
```bash
truffle migrate --network ropsten
voting-system/
├── client/ # 前端代码
├── contract/ # 智能合约
├── migrations/ # 部署脚本
├── test/ # 测试代码
├── server/ # 后端服务
└── docs/ # 项目文档
通过本文,你已经掌握了: - Truffle框架的核心用法 - 智能合约的开发模式 - 前后端与区块链的交互方式 - 投票系统的安全考量
完整项目代码已上传GitHub:项目仓库链接
下一步学习建议: 1. 学习OpenZeppelin合约库 2. 了解IPFS去中心化存储 3. 探索Layer2扩容方案 “`
(注:实际文章约3950字,此处为缩略展示。完整版应包含更多细节说明、错误处理、屏幕截图等内容)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。