eosio.forum 智能合约开发教程第二期: 投票的流程解析

本文为 dfuse 与 EOS Studio 合作内容,原文由 EOS Studio 发布  

我们将在近一段时间内陆续推出多期的系列教程,深度详解一些开源的 EOS 智能合约项目。我们将仔细挑选那些内容优质、设计精心、并可以成功构建的合约示例,其中的一些已经在 EOS 主网上广泛使用。通过本次系列教程,我们希望能为 EOSIO 上的 dApp 开发者提供更多的学习资料,并帮助他们了解更多智能合约的设计模式和应用场景。

第一期中,我们讨论了 eosio.forum 的动机以及如何在 EOS 主网上开发和使用。在本文中,我们将继续解析创建提案并对其进行投票的基本流程。该流程将分为四个阶段:提案 (Proposal) ,投票 (Voting) ,冻结 (Freeze) 和清除 RAM (Clearing Ram) 。

快速开始

我们将使用 EOS Studio Web 和 dfuse 的 On-Demand Network 进行演示,因此您无需额外花费时间来配置本地的开发环境。

配置

  • 打开 eosio.forum (https://app.eosstudio.io/dfuseio/eosio.forum)  ,单击 fork 按钮以制作您自己的项目副本;
  • 为了减少演示过程中的等待时间,我们将把等待时间从 默认的3 天修改为 5 分钟。打开 include/forum.hpp 文件,在代码第70行将 FREEZE_PERIOD_IN_SECONDS 的值更改为300。此值的用法将在后面说明;
  • 单击 build 按钮以重新构建智能合约并重新生成 wasm 和 abi 文件;
  • 创建一个新帐户并部署刚刚创建的合约。为了便于演示,我们假设创建的帐户名称为 eosio.forum ;
  • 创建一些其他的帐户,一部分用于创建提案 ( proposer ),另一部分用于进行投票(voter1, voter2, …) ;

步骤1 : 提案

任何持有 EOS 代币的有效帐户都可以在社区创建提案。调用此操作将消耗一些 RAM 来保存提案的内容。在创建新提案之前,让我们打开 proposer 账号,并留意其当前的 RAM 使用情况。一切就绪后,让我们切换到 EOS Studio 的 Contract Inspector (合约查看器) 界面,并运行 propose() 操作:

// Execute action *propose* with parameters
// Use proposer@active to sign
proposer: "proposer"
proposal_name: "usesys"
title: "Use SYS as the core symbol"
proposal_json: { "type": "referendum-v1", "content": "Should EOS change its symbol to SYS?" }
expires_at: "2020-01-01T00:00:00"

该笔交易需要由提议者 proposer 签名。所有进行中的提案都自动被编入 eosio::name 类型中的 proposal_name 里以供索引。此举也更易于给提案进行符合 eosio 类型的命名。提案的内容包含一个 title 标题字符串(最多 1024 个字符)和一个 Proposal JSON Structure Guidelines 格式的 proposal_json 字符串。每个提案还需要有一个截止期限 expires_at ,这个时间点需要是 action 执行的时间到未来 6 个月之间。我们将在步骤 3 中解释如何使用它。

创建完成后,如果您再检查 proposer 账户下 RAM 的使用情况,可以看到在和以上步骤相同的参数设置下,RAM 增加了约 480 个字节。消耗 RAM 的设定是为了防止出现大量的垃圾提案和内容,以便参与者可以优先讨论和表决一些真正重要的问题。当议案完成整个周期后,eosio.forum 将允许您安全地删除提案并回收已消耗的 RAM(步骤4)。

已发布的提案和内容会记录在 proposals 表格中,以便随时查看:

步骤2:投票

当提案被成功创建后,参与者就可以通过 vote() 操作对其进行投票。接下来,让我们继续使用之前创建的帐户进行投票演示。

// Execute action *vote* with parameters
// Use voter1@active to sign
voter: "voter1"
proposal_name: "usesys"
vote: 1 // positively vote
vote_json: ""// 

Execute action *vote* with parameters
// Use voter2@active to sign
voter: "voter2"
proposal_name: "usesys"
vote: 0 // negative vote
vote_json: ""// 

Execute action *vote* with parameters
// Use voter3@active to sign
voter: "voter3"
proposal_name: "usesys"
vote: 255 // abstain
vote_json: ""

请注意,其中 vote 的值是用来表示是否同意该提案,是 (1) 或否 (0)。它的可输入范围是 0-255 ,其他的值可以用来表示一些特殊含义。

投票的结果会被保存在表格 vote 中:

与提案的操作类似,参与投票者需要支付一定数量的 RAM 来保存自己的选票。在执行 vote() 操作后,查看投票者 RAM 的使用情况,可以看到它增加了大约 430 字节。在步骤4 中删除提案后,这些 RAM 也将原路退还给每个投票者。

投票者可以随时修改他们的投票结果。只需再次调用 vote() ,修改 vote 的赋值并覆盖原来的数据。 他们还可以通过 unvote() 操作来删除投票,这将完全删除网络中 vote 表格里的投票数据,并立即退还投票者的 RAM 。

步骤3:冻结

提案都是有时效性的,不能无限期地继续,因此创建提案时需要来设置一个投票的截止期限。这就是在创建提案时需要预定义 expires_at 的原因。提案创建者也可以随时通过手动调用 expire() 的操作来提前结束提案。这会将提案的 expires_at 字段修改为当前时间来替换其原始的截止时间。

现在让我们终止这个提案: 

// Execute action *expire* with parameters
// Use proposer@active to sign
proposal_name: "usesys"

当提案过期后(无论是手动终止或是到达截止期限后自动终止),该提案将进入 3 天的冻结期 (freeze) 。在冻结期内,该提案将被锁定,无法对其进行任何操作(无论是更改投票,删除投票或是清理)。这段时间中任何人都可以独自进行查询区块链数据、计算票数、生成投票结果等操作。提案的执行方式将取决于最终的投票结果。

由于我们在源代码中修改了冻结期的时长,因此我们只需要等待 5 分钟而不是 3 天。在这 5 分钟内,所有与已冻结的提案有关的操作尝试,如执行 vote() 或 unvote() 等,都会失效。

冻结期过后,有关提案和公投投票的整个过程就完成了。现在,我们可以安全地回收用于创建提案和生成投票的 RAM 。

步骤4:清理

当提案到期且冻结期结束后,任何账户都可以使用 clnproposal()  操作来释放已使用的相关 RAM 。这个操作可以帮助参与者有效回收所有用于创建提案或投票的 RAM,这些 RAM 将会被原路退还给投票者(用于投票的 RAM)和提案创建者(用于创建提案的 RAM)。

任何人都可以调用 clnproposal()  操作。由于只有冻结期结束的过期提案才可以被清理,因此将不会有任何的风险。 

// Execute action *clnproposal* with parameters
// Use any account to sign
proposal_name: "usesys"
max_count: 100

如果有很多的参与投票者,为防止交易超时,执行一次 clnproposal() 操作将最多可以移除 max_count 个投票。一旦本次提案的所有相关投票记录均被移除,提案本身也将会被删除。

现在,如果继续查看 proposer 和 voter1 等账户,会发现它们的 RAM 使用率已经回到了参与提案和投票之前的值。因此可以确认,提案完成后所有已使用的内存均被返还,不会出现内存泄漏的现象。

下一步是什么?

如果您觉得本教程有帮助,请别忘了点赞或关注我们的微信公众号黑曜石实验室 (Obsidianlabs),币乎号 EOSStudio,我们会持续更新更多的产品信息、技术文章和精彩内容。

深度解析 EOS 合约:eosio.forum

- 第一部分: EOSIO 公投系统

- 第二部分: 投票的流程解析

- 第三部分: 源代码的深度解读

非常感谢 dfuse 团队为本期教程的编写提供的诸多帮助!

发布了76 篇原创文章 · 获赞 2 · 访问量 9829

猜你喜欢

转载自blog.csdn.net/weixin_43891115/article/details/102908807