首页>行情>正文

从零开始,以太坊开发实例—构建一个简单的投票DApp

2026-06-23
OKX欧易app

OKX欧易app

欧易交易所app是全球排名第一的虚拟货币交易所,注册领取6万元盲盒礼包!

APP下载 官网注册

币安app

binance币安交易所app

币安交易所app是全球排名第一的虚拟货币交易所,注册领取盲盒礼包!

APP下载 官网注册

从零开始,以太坊开发实例—构建一个简单的投票DApp

从零开始,以太坊开发实例—构建一个简单的投票DApp

以太坊,作为全球领先的智能合约平台,不仅加密货币的基石,更催生了去中心化应用(DApps)的蓬勃发展,对于许多开发者而言,踏入以太坊开发的世界,最有效的方式莫过于通过一个具体的实例来学习,本文将以一个简单但功能完整的“投票DApp”为例,带你走过以太坊开发的核心流程,包括环境搭建、智能合约编写、测试、部署以及与前端交互的初步概念。

开发环境准备:工欲善其事,必先利其器

在开始编码之前,我们需要准备以下开发环境:

  1. Node.js 和 npm:JavaScript 运行时环境和包管理器,建议从官网下载并安装 LTS 版本。
  2. Truffle Suite:一套强大的以太坊开发框架,包含智能合约编译、测试、部署等功能。
    npm install -g truffle
  3. Ganache:一个个人区块链,用于本地开发和测试,它会为你提供一个模拟的以太坊网络,并分配 10 个测试账户,每个账户都有 100 个模拟 ETH。
    • 可以从 Ganache 官网下载桌面版,或通过 npm install -g ganache 命令安装命令行版本。
  4. MetaMask:浏览器钱包插件,用于与以太坊网络交互(包括本地测试网络和主网),从 Chrome 等浏览器的应用商店安装。
  5. 代码编辑器:推荐使用 Visual Studio Code,并安装 Solidity 插件,以获得更好的代码提示和高亮。

创建项目结构

  1. 创建一个新的项目文件夹,voting-dapp。
    mkdir voting-dapp
    cd voting-dapp
  2. 使用 Truffle 初始化项目:
    truffle init

    这会创建以下标准目录结构:

    • contracts/:存放 Solidity 智能合约文件。
    • migrations/:存放部署脚本文件。
    • test/:存放测试文件。
    • truffle-config.js:Truffle 配置文件。

编写智能合约:投票DApp的核心

我们的投票DApp将允许创建投票,并让参与者对特定选项进行投票。

  1. 在 contracts 目录下创建一个新的 Solidity 文件,命名为 Voting.sol。
  2. 编写合约代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Voting {
    // 定义投票选项的结构体
    struct Option {
        string name;
        uint voteCount;
    }
    // 定义提案的结构体
    struct Proposal {
        string description;
        mapping(address => bool) hasVoted; // 记录用户是否已投票
        Option[] options; // 投票选项数组
    }
    // 存储所有提案的映射,key为提案ID,value为提案
    mapping(uint => Proposal) public proposals;
    uint public proposalCount;
    // 提案创建者
    address public owner;
    // 构造函数,设置合约所有者
    constructor() {
        owner = msg.sender;
    }
    // 创建新提案
    function createProposal(string memory _description, string[] memory _optionNames) public {
        require(msg.sender == owner, "Only owner can create proposals");
        proposalCount++;
        Proposal storage proposal = proposals[proposalCount];
        proposal.description = _description;
        for (uint i = 0; i < _optionNames.length; i++) {
            proposal.options.push(Option({
                name: _optionNames[i],
                voteCount: 0
            }));
        }
    }
    // 对提案的某个选项进行投票
    function vote(uint _proposalId, uint _optionIndex) public {
        Proposal storage proposal = proposals[_proposalId];
        require(!proposal.hasVoted[msg.sender], "You have already voted for this proposal");
        require(_proposalId > 0 && _proposalId <= proposalCount, "Proposal does not exist");
        require(_optionIndex < proposal.options.length, "Option does not exist");
        proposal.hasVoted[msg.sender] = true;
        proposal.options[_optionIndex].voteCount++;
    }
    // 获取提案的选项数量
    function getProposalOptionsCount(uint _proposalId) public view returns (uint) {
        return proposals[_proposalId].options.length;
    }
    // 获取提案的某个选项信息
    function getOption(uint _proposalId, uint _optionIndex) public view returns (string memory, uint) {
        return (proposals[_proposalId].options[_optionIndex].name, proposals[_proposalId].options[_optionIndex].voteCount);
    }
}

合约解析:

编写迁移(部署)脚本

为了让 Truffle 知道如何部署我们的合约,我们需要在 migrations 目录下创建一个新的迁移脚本。

  1. 在 migrations 目录下创建文件 2_deploy_contracts.js(数字前缀表示部署顺序)。
  2. 编写脚本:
const Voting = artifacts.require("Voting");
module.exports = function (deployer) {
  // 部署 Voting 合约
  // 可以在这里传入初始参数,如果构造函数有的话
  // deployer.deploy(Voting, "Initial Proposal Description", ["Option1", "Option2"]);
  // 但我们的合约构造函数没有参数,所以直接部署
  deployer.deploy(Voting);
};

编写测试

Truffle 使用 Mocha 和 Chai 进行测试,在 test 目录下创建 voting.test.js 文件:

const Voting = artifacts.require("Voting");
contract("Voting", (accounts) => {
    let votingInstance;
    const owner = accounts[0];
    const voter1 = accounts[1];
    const voter2 = accounts[2];
    beforeEach(async () => {
        votingInstance = await Voting.new();
    });
    it("should have an owner", async () => {
        const contractOwner = await votingInstance.owner();
        assert.equal(contractOwner, owner, "The owner is not correct");
    });
    it("should allow the owner to create a proposal", async () => {
        const description = "What should we have for lunch?";
        const optionNames = ["Pizza", "Sushi", "Burger"];
        await votingInstance.createProposal(description, optionNames, { from: owner });
        const proposalCount = await votingInstance.proposalCount();
        assert.equal(proposalCount.toNumber(), 1, "Proposal count should be 1");
        const retrievedDescription = await votingInstance.proposals(1).description;
        assert.equal(retrievedDescription, description, "Proposal description is incorrect");
        const optionsCount = await votingInstance.getProposalOptionsCount(1);
        assert.equal(optionsCount.toNumber(), 3, "Options count is incorrect");
    });
    it("should allow a voter to vote", async () => {
        await votingInstance.createProposal("Favorite color?", ["Red", "Blue", "Green"], { from: owner });
        await votingInstance.vote(1, 0, { from: voter1 }); // 投给第一个选项 "Red"
        const redVotes = await votingInstance.getOption(1, 0);
        assert.equal(redVotes[1].toNumber(), 1, "Red vote count should be 1");
        const hasVoted = await votingInstance.proposals(1).hasVoted(voter1);
        assert.equal(hasVoted, true, "Voter should have voted");
    });
    it("should not allow a voter to vote twice", async () => {
        await votingInstance.createProposal("Favorite color?", ["Red", "Blue", "Green"], { from: owner });
        await votingInstance.vote(1, 0, { from: voter1 });
        try {
            await votingInstance.vote(1, 1, { from: voter1 });
            assert.fail("Expected revert but none was received");
        } catch (error) {
            assert.include(error.message, "You have already voted for this proposal");
        }
    });
});

运行测试: 在项目根目录下运行:

truffle test

Truffle 会自动启动本地测试网络(如果未启动),运行测试并输出结果。

部署到本地 Ganache 网络

欧艺交易所账户解冻时间详解

欧艺交易所账户解冻时间详解 在数字化时代,在线交易平台为投资者提供了极大的便利,当涉及到资金安全和账户管理时,用户往往需要面对各种挑战,欧艺交易所作为一家知名的数字货币交易平台,其账户解冻流程的时效性直接关系到用户的交易体验和资金安全,本文将详细解析欧艺交易

韩国以太坊淘金热,技术野心与地缘政治下的加密货币掘金

韩国以太坊淘金热,技术野心与地缘政治下的加密货币掘金 当全球加密货币市场在监管的寒流与技术的浪潮中起伏不定时,一个东亚国家正以前所未有的热情和决心,掀起了另一场“挖矿”热潮,这场热潮的主角不是比特币,而是以太坊,而这场掘金行动的地点,正是科技与娱乐产业高度

自己动手发个币到底难不难?聊聊我折腾一晚上的真实经历

前几天跟朋友喝酒,他神神秘秘说想搞个自己的币,问我有没有路子。我第一反应是这玩意儿不得几万块找外包?结果回家自己搜了搜,发现现在一键发币的工具多得离谱,干脆自己试了一遍。 先说结论:真没想象中那么玄乎,但也别指望点一下就能暴富。 我用的那个平台就不说名字了,

透明币 钱包,bob波币钱包容易被抓吗

一、有哪些500元左右,能放硬币的短款钱包可以推荐折叠钱包。这款钱包出自日本独立潮牌“m+”,他家基本一向以制作一些功能性、设计感强的小配饰见长。本次推荐的折叠立体钱包曾被StyleStore首页推荐,推出后商品的反响和口碑都非常不错。这款钱包走了一个“麻雀虽小,五脏俱全

狗狗币国际市场价格,波动背后的社区与逻辑

狗狗币国际市场价格,波动背后的社区与逻辑 狗狗币(DOGE)作为最早诞生的“模因币”之一,其国际市场价格始终加密货币市场的焦点,自2021年 Elon Musk 多次公开“喊单”以来,DOGE 价格经历了从“网络玩笑”到“现象级资产”的蜕变,波动性远超主流加密货币,背后交织着社区

GIGGLE币,2026年能否跻身主流加密货币之列?

GIGGLE币,2026年能否跻身主流加密货币之列? 在加密货币市场,“主流币”的标签往往意味着更广泛的市场认可、更高的流动性、更强的技术生态以及稳定的社区支持,随着2026年的临近,投资者和行业观察者对新兴加密资产的关注度持续升温,GIGGLE币(下称“GIGGLE”)是否具备冲

从Oyi到OKX,钱包升级背后的安全与创新之旅

从Oyi到OKX,钱包升级背后的安全与创新之旅 随着数字货币市场的蓬勃发展,交易平台及其配套服务的安全性与创新性成为了用户选择的重要考量因素,知名加密货币交易所Oyi正式宣布品牌升级,更名为OKX,并同步推出了全新的数字钱包解决方案,这一举措不仅标志着其品牌形象的焕新,

货币钱包没有zec,五大数字货币钱包有哪些

一、数字钱包那个好用imTokenimToken是一款支持ETH以及 ERC-20代币、比特币HD钱包以及隔离见证、EOS以及 EOS主网其他代币的数字货币钱包,且一套助记词可创建多个币种的钱包账户,从而告别了繁复的备份管理,是一款多链钱包。imToken支持数字货币的收发、以太系列的币币交易,

FANTC收币,数字资产流通的新机遇与理性选择

FANTC收币,数字资产流通的新机遇与理性选择 在数字经济蓬勃发展的今天,数字资产交易已成为全球资本流动的重要形态。“FANTC收币”作为近年来备受关注的交易行为,不仅是投资者实现资产配置的途径,更折射出数字货币市场日益成熟的生态逻辑。 FANTC作为具有特定应用场景的数

狗狗币被骗走怎么办?别慌!这些方法或能帮你挽回损失

狗狗币被骗走怎么办?别慌!这些方法或能帮你挽回损失 近年来,狗狗币凭借社区热度 Elon Musk 等名人的推动,成为大众熟知的加密货币之一,但随之而来的诈骗案件也屡见不鲜,如果不慎被骗走狗狗币,很多人会陷入焦虑——难道只能自认倒霉?其实从紧急止损、证据收集、平台举报

OE交易所C2C交易法币卖出指南,轻松实现DOT跨链变现

OE交易所C2C交易法币卖出指南,轻松实现DOT跨链变现 在加密货币领域,将数字资产转化为法币是投资者最常见的需求之一,对于持有DOT(波卡币)的用户而言,如何安全、高效地将这一跨链资产变现为法定货币,是关注的焦点,OE交易所作为全球领先的数字资产交易平台,其C2C(用户

正规比特币挖矿企业,现在主流的比特币挖矿网站有哪些

一、现在主流的比特币挖矿网站有哪些现在主流的比特币挖矿网站主要有比特币中国、火币网、OKCoin币行等,但这些网站都已经在全年陆陆续续关闭中国大陆用户访问通道,要是想要入场比特币的话,还是转战国外比较友好,可以选择与国内矿企合作,出海挖矿,例如选择世链矿业这种优

2024年11月10日 WOO币今日行情走势¥1.57

1.WOO币价格:$0.22 2.2024年11月10日 WOO币今日行情走势1.57币价格:1.57 3.24H最高:1.59 4.24H成交额:3.19亿 5.最大发行量:22.24亿 6.24H换手:11.04% 7.24H最低:1.48 8.24H成交量:2.03亿 9.当前发行量:22.24亿 10.24H波幅:7.86% 11.历史最高:12.69 12.最大市值:

OKX交易所官网,您的全球数字资产交易首选平台

OKX交易所官网,您的全球数字资产交易首选平台 在数字经济蓬勃发展的今天,数字资产交易已成为全球投资者关注的焦点,作为行业领先的加密货币交易平台之一,OKX交易所官网(www.okx.com)凭借其安全稳定的产品服务、丰富的交易品种以及创新的科技体验,为用户打造了一个全方位

O易交易所,连接全球,专业赋能,为您的交易之路保驾护航

O易交易所,连接全球,专业赋能,为您的交易之路保驾护航 在数字经济高速发展的今天,数字资产交易已成为全球资本流动的重要引擎,作为行业领先的数字资产交易平台,O易交易所(OEX)始终以“为全球用户提供专业交易服务”为使命,凭借技术创新、安全合规与全球化布局,为来自

OK欧义交易所事件风波,信任危机与行业反思

OK欧义交易所事件风波,信任危机与行业反思 加密货币市场再起波澜,焦点集中于“OK欧义交易所事件”,这场突如其来的风波,不仅让OK欧义交易所的用户陷入焦虑,也为整个加密货币行业敲响了警钟,引发了关于交易所安全性、透明度及监管合规性的广泛讨论。 突如其来的“黑天鹅”

笔记本挖矿比特币,用笔记本在家挖矿,一天可以挖几个比特币

一、笔记本能拿去挖矿吗结论:笔记本电脑确实可以用于挖矿,但效率和收益与专业矿机相比存在差距。以下是更直观的解释:笔记本电脑确实可以参与挖矿,特别是那些采用Proof of Work(工作量证明)机制的虚拟货币。其基本原理是通过哈希值计算获得奖励,因此只要具备运算能力,

狗狗币与MT4平台的碰撞,加密货币交易的新可能?

狗狗币与MT4平台的碰撞,加密货币交易的新可能? 在加密货币的热潮中,狗狗币(DOGE)凭借其社区热度与“ meme 币”标签持续吸引关注,而MT4平台作为外汇交易领域的“老牌工具”,则以强大的技术分析功能闻名,当狗狗币遇上MT4,会碰撞出怎样的交易火花?这或许是不少加密货币

欧一交一所露娜冻结,冰封的交涉与沉寂的星辰

欧一交一所露娜冻结,冰封的交涉与沉寂的星辰 欧一交一所露娜冻结——这串看似冰冷的代码与名称组合,背后却牵动着一场关乎星际信任与合作的重要事件,它并非一次简单的技术故障,更像是一个象征,标志着在广袤宇宙中,人类精心构建的沟通桥梁与协作机制,遭遇了一场突如其来

聚币交易所靠谱吗?深度解析其安全性与合规性

聚币交易所靠谱吗?深度解析其安全性与合规性 在数字货币投资领域,交易所的选择直接关系到资产安全与交易体验,“聚币交易所靠谱吗”这一问题,一直是投资者关注的焦点,要客观评估其可靠性,需从平台背景、安全机制、合规性及用户口碑等多维度综合分析。 平台背景与运营历史