:2026-06-09 20:09 点击:3
以太坊作为全球领先的智能合约平台,不仅仅是一种加密货币,更是一个强大的去中心化应用(DApp)开发平台,其图灵完备的智能合约功能,使得开发者能够构建无需信任第三方、自动执行、公开透明的复杂应用,本文将以一个“去中心化投票应用”为例,详细阐述以太坊完整应用实例的构建过程,涵盖从智能合约设计、前端交互到整体部署与使用的全流程。
场景: 假设我们需要为一个社区选举或重要决策构建一个投票系统。
核心需求:
智能合约是DApp的后端逻辑,部署在以太坊区块链上,对于投票应用,我们需要设计一个能够管理候选人、记录投票、统计结果的合约。
开发环境准备:
合约主要功能与状态变量:
状态变量:
string public votingName; // 投票名称uint256 public votingStartTime; // 投票开始时间戳uint256 public votingEndTime; // 投票结束时间戳address public owner; // 合约部署者,拥有某些管理权限mapping(address => bool) public hasVoted; // 记录地址是否已投票mapping(string => uint256) public voteCounts; // 记录每个候选人的票数string[] public candidates; // 候选人列表函数:
constructor(string memory _votingName, string[] memory _candidates, uint256 _startTime, uint256 _endTime) public:构造函数,初始化投票名称、候选人列表、开始和结束时间,部署者自动成为owner。function vote(string memory candidateName) public:投票函数,调用者需满足:投票在有效时间内、尚未投票、候选人存在,投票成功后,标记该地址已投票,并增加候选人票数。function addCandidate(string memory candidateName) public onlyOwner:添加候选人函数,仅owner可调用。function getVoteCount(string memory candidateName) public view returns (uint256):获取某候选人票数。function getTotalVotes() public view returns (uint256):获取总投票数。modifier onlyOwner() { require(msg.sender == owner, "Only owner can perform this action"); _; }:修饰符,限制仅owner可执行某些函数。合约编写示例(简化版):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Voting {
string public votingName;
uint256 public votingStartTime;
uint256 public votingEndTime;
address public owner;
mapping(address => bool) public hasVoted;
mapping(string => uint256) public voteCounts;
string[] public candidates;
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can perform this action");
_;
}
modifier votingActive() {
require(block.timestamp >= votingStartTime && block.timestamp <= votingEndTime, "Voting is not active");
_;
}
constructor(string memory _votingName, string[] memory _candidates, uint256 _startTime, uint256 _endTime) {
votingName = _votingName;
candidates = _candidates;
votingStartTime = _startTime;
votingEndTime = _endTime;
owner = msg.sender;
}
function vote(string memory candidateName) public votingActive {
require(!hasVoted[msg.sender], "You have already voted");
bool candidateExists = false;
for (uint i = 0; i < candidates.length; i++) {
if (keccak256(bytes(candidates[i])) == keccak256(bytes(candidateName))) {
candidateExists = true;
break;
}
}
require(candidateExists, "Candidate does not exist");
hasVoted[msg.sender] = true;
voteCounts[candidateName]++;
}
function addCandidate(string memory candidateName) public onlyOwner {
candidates.push(candidateName);
}
function getVoteCount(string memory candidateName) public view returns (uint256) {
return voteCounts[candidateName];
}
function getTotalVotes() public view returns (uint256) {
uint total = 0;
for (uint i = 0; i < candidates.length; i++) {
total += voteCounts[candidates[i]];
}
return total;
}
}
智能合约本身无法直接与用户交互,需要前端应用来调用合约函数并展示数据。
技术栈选择:
前端主要功能:
前端核心逻辑(伪代码/片段):
连接钱包:
let provider;
let signer;
let contract;
async function connectWallet() {
if (window.ethereum) {
provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
signer = provider.getSigner();
// 合约地址需要替换为实际部署后的地址
contract = new ethers.Contract(CONTRACT_ADDRESS, VotingABI, signer);
// 更新UI,显示钱包地址等
} else {
alert("Please install MetaMask!");
}
}
获取候选人列表并显示:
async function displayCandidates() {
const candidates = await contract.getCandidates(); // 假设合约有此函数或通过candidates数组长度遍历
const candidateSelect = document.getElementById('candidateSelect');
candidates.forEach(candidate => {
const option = document.createElement('option');
option.value = candidate;
option.textContent = candidate;
candidateSelect.appendChild(option);
});
}
投票功能:
async function vote() {
const candidateName = document.getElementById('candidateSelect').value;
try {
const tx = await contract.vote(candidateName);
await tx.wait(); // 等待交易确认
alert("Vote submitted successfully!");
// 更新投票结果
displayResults();
// 检查并更新用户投票状态
} catch (error) {
console.error(error);
alert("Vote failed: " + error.message);
}
}
显示投票结果:
async function displayResults() {
const candidates = await contract.getCandidates();
const resultsDiv = document.getElementById('results');
resultsDiv.inn
erHTML = '';
for (const candidate of candidates) {
const voteCount = await contract.getVoteCount(candidate);
const resultItem = document.createElement('div');
resultItem.textContent = `${candidate}: ${voteCount} votes`;
resultsDiv.appendChild(resultItem);
}
}
部署智能合约:
前端应用部署:
本文由用户投稿上传,若侵权请提供版权资料并联系删除!