Solidity学习-投票合约示例

以下的合约有一些复杂,但展示了很多Solidity的语言特性。它实现了一个投票合约。 当然,电子投票的主要问题是如何将投票权分配给正确的人员以及如何防止被操纵。 我们不会在这里解决所有的问题,但至少我们会展示如何进行委托投票,同时,计票又是 自动和完全透明的 。

我们的想法是为每个(投票)表决创建一份合约,为每个选项提供简称。 然后作为合约的创造者——即主席,将给予每个独立的地址以投票权。

地址后面的人可以选择自己投票,或者委托给他们信任的人来投票。

在投票时间结束时,winningProposal() 将返回获得最多投票的提案。

代码如下:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

/// @title 委托投票
contract Ballot {
   
  
    // 定义投票者
    struct Voter {
        uint weight; // 计票的权重
        bool voted;  // 若为真,代表该人已投票
        address delegate; // 被委托人
        uint vote;   // 投票提案的索引
    }

    // 定义被投票者
    struct Proposal {
        bytes32 name;   // 简称(最长32个字节)
        uint voteCount; // 得票数
    }



    address public chairperson;
   // 这声明了一个状态变量,为每个可能的地址存储一个 `Voter`。
    mapping(address => Voter) public voters;

     // 一个 `Proposal` 结构类型的动态数组
    Proposal[] public proposals;


    /// 为 `proposalNames` 中的每个提案,创建一个新的(投票)表决
    constructor(bytes32[] memory proposalNames) {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;
        //对于提供的每个提案名称,
        //创建一个新的 Proposal 对象并把它添加到数组的末尾。
        for (uint i = 0; i < proposalNames.length; i++) {
            // `Proposal({...})` 创建一个临时 Proposal 对象,
            // `proposals.push(...)` 将其添加到 `proposals` 的末尾
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount: 0
            }));
        }
    }
    // 授权 `voter` 对这个(投票)表决进行投票
    // 只有 `chairperson` 可以调用该函数。
    function giveRightToVote(address voter) external {
        // 若 `require` 的第一个参数的计算结果为 `false`,
        // 则终止执行,撤销所有对状态和以太币余额的改动。
        // 在旧版的 EVM 中这曾经会消耗所有 gas,但现在不会了。
        // 使用 require 来检查函数是否被正确地调用,是一个好习惯。
        // 你也可以在 require 的第二个参数中提供一个对错误情况的解释。
        require(
            msg.sender == chairperson,
            "Only chairperson can give right to vote."
        );
        //判断是否已经投过票了
        require(
            !voters[voter].voted,
            "The voter already voted."
        );
        require(voters[voter].weight == 0);
        voters[voter].weight = 1;
    }



 /// 把你的投票委托到投票者 `to`。
    function delegate(address to) external {
        // 传引用
        Voter storage sender = voters[msg.sender];
        require(sender.weight != 0, "You have no right to vote");
        require(!sender.voted, "You already voted.");

        require(to != msg.sender, "Self-delegation is disallowed.");

        // 委托是可以传递的,只要被委托者 `to` 也设置了委托。
        // 一般来说,这种循环委托是危险的。因为,如果传递的链条太长,
        // 则可能需消耗的gas要多于区块中剩余的(大于区块设置的gasLimit),
        // 这种情况下,委托不会被执行。
        // 而在另一些情况下,如果形成闭环,则会让合约完全卡住。
        while (voters[to].delegate != address(0)) {
            to = voters[to].delegate;

            // 不允许闭环委托
            require(to != msg.sender, "Found loop in delegation.");
        }

        // `sender` 是一个引用, 相当于对 `voters[msg.sender].voted` 进行修改
        Voter storage delegate_ = voters[to];

        // Voters cannot delegate to accounts that cannot vote.
        require(delegate_.weight >= 1);

        // Since `sender` is a reference, this
        // modifies `voters[msg.sender]`.
        sender.voted = true;
        sender.delegate = to;

        if (delegate_.voted) {
            // 若被委托者已经投过票了,直接增加得票数
            proposals[delegate_.vote].voteCount += sender.weight;
        } else {
            // 若被委托者还没投票,增加委托者的权重
            delegate_.weight += sender.weight;
        }
    }

 /// 把你的票(包括委托给你的票),
    /// 投给提案 `proposals[proposal].name`.
    function vote(uint proposal) external {
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "Already voted.");
        sender.voted = true;
        sender.vote = proposal;

        // 如果 `proposal` 超过了数组的范围,则会自动抛出异常,并恢复所有的改动
        proposals[proposal].voteCount += sender.weight;
    }

  /// @dev 结合之前所有的投票,计算出最终胜出的提案
    function winningProposal() public view returns (uint winningProposal_)
    {
        uint winningVoteCount = 0;
        for (uint p = 0; p < proposals.length; p++) {
            if (proposals[p].voteCount > winningVoteCount) {
                winningVoteCount = proposals[p].voteCount;
                winningProposal_ = p;
            }
        }
    }  
    
     // 计算获胜的提案
    // function winningProposal() public view returns (uint winningProposal) {
    //     uint winningVoteCount = 0;
    //     for (uint p = 0; p < proposals.length; p++) {
    //         if (proposals[p].voteCount > winningVoteCount) {
    //             winningVoteCount = proposals[p].voteCount;
    //             winningProposal = p;
    //         }
    //     }
    // }

    
     // 调用 winningProposal() 函数以获取提案数组中获胜者的索引,并以此返回获胜者的名称
     //winnerName 函数调用 winningProposal() 函数,并使用其返回值来访问 proposals 数组。
    function winnerName() public view returns (bytes32 winnerName_)
    {
        winnerName_ = proposals[winningProposal()].name;
    }



}

测试

在你的合约中,构造函数需要一个参数 proposalNames,它是一个 bytes32 数组。因此,你需要在部署时提供这个参数。

在“Deploy & Run Transactions”面板中,找到“Deploy”按钮下方的输入框并输入提案名称列表。

例如,你可以输入以下内容:

["0x50726f706f73616c310000000000000000000000000000000000000000000000", "0x50726f706f73616c320000000000000000000000000000000000000000000000"]

在这里插入图片描述
部署成功:

在这里插入图片描述
查看生成的账户:
在 Deploy & Run Transactions 面板中,你会看到一个 ACCOUNT 下拉菜单。这个菜单中列出了所有生成的账户地址及其余额。你可以从中选择一个地址进行测试。

选择和复制账户地址:

点击 ACCOUNT 下拉菜单,选择一个账户。
复制选中的账户地址。

在这里插入图片描述

  1. 授权投票权 (giveRightToVote)
    在 giveRightToVote 的输入框中输入授权投票者的地址。

示例:

在这里插入图片描述
2. 委托投票 (delegate)
在 delegate 的输入框中输入被委托人的地址(可以是同一个账户或其他账户)
在这里插入图片描述

这里测试发现输入的都会这个提示,这个待验证处理

  1. 投票 (vote)
    在 vote 的输入框中输入提案索引。

在这里插入图片描述
4. 查看主席 (chairperson)
点击 chairperson 按钮查看合约的主席地址。

在这里插入图片描述
5. 查看提案信息 (proposals)
在 proposals 的输入框中输入提案索引。

在这里插入图片描述
点击 proposals 按钮查看提案的名称和票数。

在这里插入图片描述
在这里插入图片描述
6. 查看投票者信息 (voters)
在 voters 的输入框中输入投票者的地址。

在这里插入图片描述
7. 获胜提案名称 (winnerName)
点击 winnerName 按钮查看当前获胜提案的名称。

在这里插入图片描述
8. 计算获胜提案 (winningProposal)
点击 winningProposal 按钮查看当前获胜提案的索引。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/666862.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

显示器与电脑如何分屏显示?

1.点击电脑屏幕右键--显示设置 2、然后找到屏幕---找到多显示器---选择扩展显示器

亚马逊云科技峰会盛大举行 | 光环新网携光环云数据以高性能智算服务助力企业创新发展

2024年5月29日&#xff0c;云计算行业的年度盛典”2024亚马逊云科技中国峰会”在上海世博中心再次盛大启幕。作为全球领先的云计算服务提供商&#xff0c;亚马逊云科技峰会聚焦前沿科技&#xff0c;与来自不同行业、不同科技领域的优秀企业和用户共同探索AI时代的云端创新发展。…

游戏逆向工具分析及解决方案

游戏逆向&#xff0c;是指通过各类工具对游戏进行反编译及源码分析&#xff0c;尝试分析游戏的实现逻辑的过程。这个过程需要使用解密、反编译、解压缩等技术&#xff0c;目的是还原或分析出游戏的代码逻辑及资源。 游戏逆向工具可以按照不同功能进行划分&#xff0c;如&#…

分布式任务队列系统 celery 原理及入门

基本 Celery 是一个简单、灵活且可靠的分布式任务队列系统&#xff0c;用于在后台执行异步任务处理大量消息。支持任务调度、任务分发和结果存储&#xff0c;并且可以与消息代理&#xff08;如 RabbitMQ、Redis 等&#xff09;一起工作&#xff0c;以实现任务的队列管理和执行…

对于vsc中的vue命令 vue.json

打开vsc 然后在左下角有一个设置 2.点击用户代码片段 3.输入 vue.json回车 将此代码粘贴 &#xff08;我的不一定都适合&#xff09; { "vue2 template": { "prefix": "v2", "body": [ "<template>", " <…

更新详情 | Flutter 3.22 与 Dart 3.4

作者 / Michael Thomsen 过去几个月&#xff0c;Dart & Flutter 部门可谓忙碌非凡&#xff0c;但我们很高兴地宣布&#xff0c;Flutter 3.22 和 Dart 3.4 已经在今年的 Google I/O 大会上精彩亮相&#xff01; Google I/Ohttps://io.google/2024/intl/zh/ 我们始终致力于提…

【调试笔记-20240530-Linux-在 OpenWRT-23.05 上为 nginx 配置 HTTPS 网站】

调试笔记-系列文章目录 调试笔记-20240530-Linux-在 OpenWRT-23.05 上为 nginx 配置 HTTPS 网站 文章目录 调试笔记-系列文章目录调试笔记-20240530-Linux-在 OpenWRT-23.05 上为 nginx 配置 HTTPS 网站 前言一、调试环境操作系统&#xff1a;OpenWrt 23.05.3调试环境调试目标…

CS61C | lecture2

# CS61C | lecture2 C 语言是一种编译语言。C 编译器将 C 程序映射到特定与体系结构的机器代码(实际上是一串 0 和 1)。 而 Java 会通过 JVM(Java 虚拟机) 将代码转换为独立于架构的字节码。 Python 则会直接解释代码。C 不会直接解释代码&#xff0c;而是将其编译成机器代码之…

计算机基础学习路线

计算机基础学习路线 整理自学计算机基础的过程&#xff0c;虽学习内容众多&#xff0c;然始终相信世上无难事&#xff0c;只怕有心人&#xff0c;期间也遇到许多志同道合的同学&#xff0c;现在也分享自己的学习过程来帮助有需要的。 一、数据结构与算法 视频方面我看的是青…

Bean作用域和生产周期已经Bean的线程安全问题

bean 的作用域 单例(Singletion) : Spring 容器中只有一个 bean &#xff0c;这个 bean 在整个应用程序内共享。 原话(Prototype) : 每次 getBean()&#xff0c; 都是不同的bean&#xff0c;都会创建一个实例。 请求(Request)&#xff1a;每个HTTP请求都会创建一个新的 Bean …

ARM虚拟机安装OMV

OMV(OpenMediaVault)是基于 Debian GNU/Linux 的网络连接存储&#xff08;network attached storage&#xff0c;NAS&#xff09;解决方案。它包含 SSH、(S) FTP、SMB/CIFS、DAAP 媒体服务器、rsync、 BitTorrent 等很多种服务。它可用于 x86-64 和 ARM 平台。 在x86-64平台上&…

推荐一款开源电子签章/电子合同系统

文章目录 前言一、项目介绍二、项目地址三、技术架构四、代码结构介绍五、功能模块六、功能界面首页面手写签名面板电子印章制作数字证书生成 总结 前言 大家好&#xff01;我是智航云科技&#xff0c;今天为大家分享一个免费开源的电子签字系统。 一、项目介绍 开放签电子签…

【Python】如何使用 Python 自动发送每日电子邮件报告

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

详解Spring IoCDI(二)

目录 承接上文&#xff1a;详解Spring IoC&DI &#xff08;一&#xff09; 1.IoC详解 1.1方法注解Bean 1.2方法注解要配合类注解使用 1.3定义多个对象 1.4重命名Bean 1.5扫描路径 2.DI详解 2.1DI与IoC的关系 2.2属性注入 2.3构造方法注入 2.4Setter注入 2.5 三…

【Endnote】如何在word界面加载Endnote

如何在word界面加载Endnote 方法1&#xff1a;方法2&#xff1a;从word入手方法3&#xff1a;从CWYW入手参考 已下载EndNote,但Word中没有显示EndNote&#xff0c;应如何加载显示呢&#xff1f; 方法1&#xff1a; 使用EndNote的Configure EndNote.exe 。 具体步骤为&#x…

内网安全:横向传递攻击(PTH || PTK || PTT 哈希票据传递)

内网安全&#xff1a;横向传递攻击. 横向移动就是在拿下对方一台主机后&#xff0c;以拿下的那台主机作为跳板&#xff0c;对内网的其他主机再进行后面渗透&#xff0c;利用既有的资源尝试获取更多的凭据、更高的权限&#xff0c;一步一步拿下更多的主机&#xff0c;进而达到控…

理解AdaBoost算法:简单流程概述(一)【流程理解、无数学推导】

什么是AdaBoost 算法&#xff1f; AdaBoost&#xff08;Adaptive Boosting&#xff09;算法&#xff0c;全称为 自适应提升 &#xff0c;是 一种在机器学习中用作集成方法的提升技术 。它之所以被称为自适应提升&#xff0c;因为每个实例的权重会重新分配&#xff0c;错误分类…

C语言 | Leetcode C语言题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; #define max(a, b) ((a) < (b) ? (b) : (a))int maxProfit(int* prices, int pricesSize) {int buy1 -prices[0], sell1 0;int buy2 -prices[0], sell2 0;for (int i 1; i < pricesSize; i) {buy1 max(buy1, -prices[i]);sell…

解决:【无法安装“vue.volar“扩展,因为它与当前 VIsual Studio Code 版本不兼容(版本 1.80.0)】

目录 问题复现问题分析解决步骤1、进入VSCode插件市场&#xff0c;搜索Vue.volar2、点击搜索结果&#xff0c;进入详情页面3、下载.vsix文件完成后&#xff0c;用解压软件打开 4、复制package.json文件&#xff0c;修改vscode版本5、保存package.json文件&#xff0c;并更新.v…

【NPS】微软NPS配置802.1x,验证域账号,动态分配VLAN(有线网络篇)

上两篇中介绍了如何配置NPS和在WLC上如何配置802.1X来实现验证域账号和动态分配VLAN&#xff0c;802.1x协议作为一种成熟的身份验证框架&#xff0c;不仅适用于无线网络&#xff0c;同样也适用于有线网络环境。这里我们将介绍如何在有线网络中部署802.1x认证&#xff0c;以验证…