本实验报告旨在记录并分析一个基于以太坊区块链的去中心化投票系统的设计与实现过程,通过本次实验,深入理解了区块链技术的核心原理,特别是智能合约的编写、部署与交互过程,并验证了区块链在解决中心化投票系统信任、透明及防篡改问题上的可行性与优势,实验结果表明,该原型系统能够实现投票过程的去中心化管理、投票记录的不可篡改以及投票结果的真实可追溯。

  1. 实验背景与意义 随着数字化时代的到来,投票系统作为民主决策的重要工具,其安全性、透明度和公正性备受关注,传统的中心化投票系统往往存在单点故障、数据易被篡改、缺乏透明度等弊端,区块链技术以其去中心化、不可篡改、可追溯和公开透明等特性,为构建安全可信的投票系统提供了全新的解决方案,本实验通过搭建一个基于以太坊的去中心化投票系统原型,旨在探索区块链在实际应用中的具体实现方法及其优势。

  2. 实验目的

    • 理解区块链技术的基本概念、工作原理及以太坊平台特性。
    • 掌握Solidity智能合约的编写、编译与部署方法。
    • 学习使用Web3.js等前端库与智能合约进行交互。
    • 体验去中心化应用(DApp)的开发流程。
    • 验证区块链在投票场景下的应用效果,分析其优缺点。
  3. 实验环境与工具

    • 操作系统: Windows 10 / macOS
    • 开发工具: Visual Studio Code
    • 区块链平台:以太坊测试网(如Ropsten, Goerli)或本地私有链(Ganache)
    • 智能合约语言: Solidity
    • 前端框架: HTML, CSS, JavaScript
    • Web3库: Web3.js
    • 钱包工具: MetaMask
    • 其他工具: Truffle框架(可选,用于合约编译、部署与测试),Node.js npm

实验原理与技术基础

  1. 区块链技

    随机配图
    术概述 区块链是一种分布式账本技术,通过密码学将数据块按时间顺序相连,形成一个不可篡改的数据链,其核心特性包括去中心化、数据不可篡改、透明可追溯、共识机制等。

  2. 以太坊与智能合约 以太坊是一个开源的、有智能合约功能的区块链平台,智能合约是部署在区块链上的自动执行的程序代码,当预设条件被触发时,合约会自动执行约定的条款,无需第三方干预。

  3. Web3.js Web3.js是一个JavaScript库,它允许与本地或远程以太坊节点进行交互,从而读取区块链数据、调用智能合约方法或发送交易。

实验设计与实现

  1. 系统架构设计 本去中心化投票系统主要由三部分组成:

    • 智能合约层: 部署在以太坊区块链上,负责定义投票规则(如投票人资格、候选人信息、投票时间限制)、记录投票数据、统计投票结果等。
    • 前端应用层: 用户交互界面,基于HTML/CSS/JavaScript开发,用户通过MetaMask钱包连接,实现查看候选人、投票、查看结果等功能。
    • 区块链网络层: 提供底层区块链服务,本实验采用以太坊测试网或Ganache模拟的私有链。
  2. 智能合约设计与实现 智能合约Voting.sol核心功能设计如下:

    • 状态变量:

      • votingContractOwner: 合约部署者地址,拥有管理权限(如添加候选人)。
      • candidates: 候选人信息映射,候选人名称为键,得票数为值。
      • voters: 记录已投票地址的映射,防止重复投票。
      • votingStartTime/votingEndTime: 投票开始和结束时间。
    • 事件(Events):

      • VotedEvent: 当有人投票时触发,记录投票人地址和候选人。
    • 函数(Functions):

      • constructor(): 构造函数,初始化合约所有者,设置投票时间。
      • addCandidate(string memory candidateName): 仅合约所有者可调用,添加候选人。
      • vote(string memory candidateName): 核心投票函数,检查投票时间、候选人是否存在、投票人是否已投票,通过后更新票数并标记投票人。
      • getVotes(string memory candidateName) public view returns (uint256): 查询指定候选人的得票数。
      • getWinner() public view returns (string memory): 获取当前得票最多的候选人(投票结束后)。
    • Solidity代码示例(简化版):

      pragma solidity ^0.8.0;
      contract Voting {
          address public votingContractOwner;
          mapping(string => uint256) public candidates;
          mapping(address => bool) public voters;
          uint256 public votingStartTime;
          uint256 public votingEndTime;
          event VotedEvent(address voter, string candidate);
          constructor(uint256 _votingDurationSeconds) {
              votingContractOwner = msg.sender;
              votingStartTime = block.timestamp;
              votingEndTime = block.timestamp + _votingDurationSeconds;
          }
          modifier onlyOwner() {
              require(msg.sender == votingContractOwner, "Only owner can call this function");
              _;
          }
          modifier duringVoting() {
              require(block.timestamp >= votingStartTime && block.timestamp <= votingEndTime, "Voting is not active");
              _;
          }
          function addCandidate(string memory candidateName) public onlyOwner {
              require(bytes(candidateName).length > 0, "Candidate name cannot be empty");
              require(candidates[candidateName] == 0, "Candidate already exists");
              candidates[candidateName] = 0;
          }
          function vote(string memory candidateName) public duringVoting {
              require(!voters[msg.sender], "You have already voted");
              require(candidates[candidateName] > 0, "Candidate does not exist");
              voters[msg.sender] = true;
              candidates[candidateName] += 1;
              emit VotedEvent(msg.sender, candidateName);
          }
          function getVotes(string memory candidateName) public view returns (uint256) {
              return candidates[candidateName];
          }
          function getWinner() public view returns (string memory) {
              uint256 maxVotes = 0;
              string memory winner;
              for (uint256 i = 0; i < candidateNames.length; i++) {
                  string memory memoryCandidateName = candidateNames[i];
                  if (candidates[memoryCandidateName] > maxVotes) {
                      maxVotes = candidates[memoryCandidateName];
                      winner = memoryCandidateName;
                  }
              }
              return winner;
          }
      }
  3. 前端应用实现

    • 用户界面: 包含候选人列表、投票按钮、投票结果显示区域、连接MetaMask按钮等。
    • 交互逻辑: 使用Web3.js连接到以太坊节点,加载已部署的智能合约实例。
      • 用户点击“连接钱包”按钮,MetaMask弹出请求,用户授权后,前端获取用户账户地址。
      • 合约所有者可通过前端调用addCandidate添加候选人。
      • 普通用户选择候选人后,点击“投票”按钮,调用vote函数,MetaMask弹出交易确认框,用户确认后发送交易。
      • 前端实时或定时调用getVotesgetWinner函数,更新投票结果。

实验过程与步骤

  1. 环境搭建: 安装Node.js, npm, Ganache(或配置以太坊测试网),安装MetaMask浏览器插件,创建测试账户。
  2. 智能合约开发: 使用VS Code编写Voting.sol智能合约代码。
  3. 智能合约编译与部署:
    • 使用Truffle框架或直接使用Remix IDE编译Solidity代码,生成ABI(应用程序二进制接口)和字节码。
    • 使用Truffle部署脚本或通过Web3.js将合约部署到以太坊测试网/Ganache,获取合约地址。
  4. 前端应用开发: 创建HTML/CSS/JavaScript文件,引入Web3.js库,编写连接钱包、调用合约函数的代码。
  5. 系统测试:
    • 启动Ganache或连接到以太坊测试网。
    • 通过MetaMask导入部署合约时使用的测试账户,并确保账户有足够的ETH(用于Gas费)。
    • 打开前端应用,连接MetaMask。
    • 合约所有者添加候选人。
    • 不同用户账户进行投票操作。
    • 查看投票结果是否正确更新,检查区块链浏览器上的交易记录。

**五、 实