EOSIO开发区块链DApp之智能合约

摘要:
示例智能合约的目的是模拟选举。创建了两个公民用户来投票给候选人。投票记录保存在EOSIO区块链中。在此示例中,所有操作都在命令模式下运行。以下是election.cpp的完整源代码:#includeusingnamespaceeosio;classelection:publiccontract{private://createthemultiindextablestostorethedata///@abitablestructcandidate{uint64_t_key;//primarykeystd::string_name;//candidatenameuint32_t_count=0;//votedcountuint64_tprimary_key()const{return_key;}};typedefeosio::multi_indexcandidates;///@abitablestructvoter{uint64_t_key;uint64_t_candidate_key;//nameofpollaccount_name_account;//thisaccounthasvoted,avoidduplicatevoteruint64_tprimary_key()const{return_key;}uint64_tcandidate_key()const{return_candidate_key;}};typedefeosio::multi_index˂N,voter,indexed_by˂N,const_mem_fun˃˃voters;//localinstancesofthemultiindexescandidates_candidates;voters_voters;uint64_t_candidates_count;public:election:contract,_candidates(s,s),_voters(s,s),_candidates_count{}//publicmethodsexposedviatheABI//oncandidates///@abiactionvoidversion(){print;};///@abiactionvoidaddc{print;uint64_tkey=_candidates.available_primary_key();//updatethetabletoincludeanewcandidate_candidates.emplace;print;};///@abiactionvoidreset(){//Getallkeysof_candidatesstd::vectorkeysForDeletion;for{keysForDeletion.push_back;}//nowdeleteeachitemforthatpollfor{autoitr=_candidates.find;if(itr!

这是一步步的用EOSIO开发区块链DApp的第二部分,这部分将主要是为EOSIO平台开发智能合约。

示例智能合约的目的是模拟选举。我创建了一个EOSIO用户来托管智能合约。创建了两个公民用户来投票给候选人。投票记录保存在EOSIO区块链中。在此示例中,所有操作都在命令模式下运行。让我们开始吧。

开发智能合约

EOSIO执行以WebAssembly标准开发的智能合约。所以我用C++开发了选举智能合约。以下是election.cpp的完整源代码:

#include <eosiolib/eosio.hpp>

using namespace eosio;

class election : public contract
{
private:
  // create the multi index tables to store the data

  /// @abi table
  struct candidate {
    uint64_t _key;       // primary key
    std::string _name;   // candidate name
    uint32_t _count = 0; // voted count

    uint64_t primary_key() const { return _key; }
  };
  typedef eosio::multi_index<N(candidate), candidate> candidates;

  /// @abi table
  struct voter {
    uint64_t _key;
    uint64_t _candidate_key; // name of poll
    account_name _account;   // this account has voted, avoid duplicate voter

    uint64_t primary_key() const { return _key; }
    uint64_t candidate_key() const { return _candidate_key; }
  };
  typedef eosio::multi_index<N(voter), voter, indexed_by<N(_candidate_key), const_mem_fun<voter, uint64_t, &voter::candidate_key>>> voters;

  // local instances of the multi indexes
  candidates _candidates;
  voters _voters;
  uint64_t _candidates_count;

public:
  election(account_name s) : contract(s), _candidates(s, s), _voters(s, s), _candidates_count(0) {}

  // public methods exposed via the ABI
  // on candidates

  /// @abi action
  void version() {
    print("Election Smart Contract version 0.0.1
");
  };

  /// @abi action
  void addc(std::string name) {
    print("Adding candidate ", name, "
");

    uint64_t key = _candidates.available_primary_key();

    // update the table to include a new candidate
    _candidates.emplace(get_self(), [&](auto &p) {
      p._key = key;
      p._name = name;
      p._count = 0;
    });

    print("Candidate added successfully. candidate_key = ", key, "
");
  };

  /// @abi action
  void reset() {
    // Get all keys of _candidates
    std::vector<uint64_t> keysForDeletion;
    for (auto &itr : _candidates) {
      keysForDeletion.push_back(itr.primary_key());
    }

    // now delete each item for that poll
    for (uint64_t key : keysForDeletion) {
      auto itr = _candidates.find(key);
      if (itr != _candidates.end()) {
        _candidates.erase(itr);
      }
    }

    // Get all keys of _voters
    keysForDeletion.empty();
    for (auto &itr : _voters) {
      keysForDeletion.push_back(itr.primary_key());
    }

    // now delete each item for that poll
    for (uint64_t key : keysForDeletion) {
      auto itr = _voters.find(key);
      if (itr != _voters.end()) {
        _voters.erase(itr);
      }
    }

    print("candidates and voters reset successfully.
");
  };

  /// @abi action
  void results() {
    print("Start listing voted results
");
    for (auto& item : _candidates) {
      print("Candidate ", item._name, " has voted count: ", item._count, "
");
    }
  };

  /// @abi action
  void vote(account_name s, uint64_t candidate_key) {
    require_auth(s);

    bool found = false;

    // Did the voter vote before?
    for (auto& item : _voters) {
      if (item._account == s) {
        found = true;
        break;
      }
    }
    eosio_assert(!found, "You're voted already!");

    // Findout the candidate by id
    std::vector<uint64_t> keysForModify;
    for (auto& item : _candidates) {
      if (item.primary_key() == candidate_key) {
        keysForModify.push_back(item.primary_key());
        break;
      }
    }

    if (keysForModify.size() == 0) {
      eosio_assert(found, "Invalid candidate id!");
      return;
    }

    // Update the voted count inside the candidate
    for (uint64_t key : keysForModify) {
      auto itr = _candidates.find(key);
      auto candidate = _candidates.get(key);
      if (itr != _candidates.end()) {
        _candidates.modify(itr, get_self(), [&](auto& p) {
          p._count++;
        });

        print("Voted candidate: ", candidate._name, " successfully
");
      }
    }

    // Add this user to voters array
    _voters.emplace(get_self(), [&](auto& p) {
      p._key = _voters.available_primary_key();
      p._candidate_key = candidate_key;
      p._account = s;
    });
  };
};

EOSIO_ABI(election, (version)(reset)(addc)(results)(vote))

注意最后一行EOSIO_ABI()是一个宏语句,用于自动生成ABI文件而不是手动编写。ABI文件用于定义提交动作处理程序。这告诉了EOSIO智能合约中处理程序的定义。

EOSIO为我们提供了多索引数据库API,可以将数据保存到区块链中。在上面的选举智能合约中,我定义了两个multi_index(类似于SQL表):候选人和选民。实际上是两个数组存储两个结构:候选者和选民。我使用C++ STL来操作multi_index,例如addupdatedelete

请注意,两个结构在开头标有/// @abi table。这是告诉EOSIO abi生成器在election.abi文件中生成ABI表。这很方便。

编译选举智能合约:

$ eosiocpp -o election.wast election.cpp

分别生成WAST和WASM文件。但这对EOSIO来说还不够。我们还需要生成ABI文件:

$ eosiocpp -g election.abi election.cpp

Visual Studio Code的可选文件

为了增强开发体验,我为Visual Studio Code(VSCode)创建了一个属性文件c_cpp_properties.json,告诉它如何查找头文件。该文件需要存储在.vscode目录中,如下所示:

EOSIO开发区块链DApp之智能合约第1张

.vscode/c_cpp_properties文件内容如下:

{
  "configurations": [
    {
      "name": "Linux",
      "includePath": [
        "${workspaceFolder}/**",
        "~/eos/contracts",
        "~/opt/boost/include"
      ],
      "defines": [],
      "compilerPath": "/usr/bin/clang++-4.0",
      "cStandard": "c11",
      "cppStandard": "c++17",
      "intelliSenseMode": "clang-x64"
    }
  ],
  "version": 4
}

启动EOSIO

一直在使用配置良好的虚拟机(在第1部分中提到)。要启动单节点Testnet服务器:

$ nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --access-control-allow-origin=* --contracts-console

单击此处获取nodeos参数的更多信息。

创建帐户

下一个任务是解锁默认钱包。EOSIO将密钥对存储在钱包中。每次服务器重启或每15分钟需要解锁一次。解锁钱包:

$ cleos wallet unlock --password ${wallet_password}

我们需要分别创建一个所有者密钥对和活动密钥对。然后将该私钥导入钱包。键入以下命令:

$ cleos create key # Create an owner key
$ cleos create key # Create an active key
$ cleos wallet import ${private_owner_key}
$ cleos wallet import ${private_active_key}

不要忘记在某个地方记录这些密钥对。

接下来的任务是创建一个新的帐户来保存选举智能合约。 键入以下命令:

$ cleos create account eosio election ${public_owner_key} ${public_active_key}

此外,为投票模拟创建两个公民:

$ cleos create account eosio voter1 ${public_owner_key} ${public_active_key}
$ cleos create account eosio voter2 ${public_owner_key} ${public_active_key}

部署智能合约

输入以下命令上传选举智能合约:

$ cleos set contract election ../election -p election

结果类似下图:

EOSIO开发区块链DApp之智能合约第2张

运行智能合约

我们可以尝试运行合约。

1.运行version操作

$ cleos push action election version '' -p election

我们可以从nodeos检查控制台输出:

EOSIO开发区块链DApp之智能合约第3张

2.增加选举候选人

$ cleos push action election addc '["Hillary Clinton"]' -p election
$ cleos push action election addc '["Donald J. Trump"]' -p election

3.显示存储在区块链中的候选数据库

$ cleos get table election election candidate

结果如图所示:

EOSIO开发区块链DApp之智能合约第4张

4.模拟投票(两位选民都被投票给唐纳德·J·特朗普)

$ cleos push action election vote '["voter1", 1]' -p voter1
$ cleos push action election vote '["voter2", 1]' -p voter2

如果voter1再次投票:

$ cleos push action election vote '["voter1", 0]' -p voter1

EOSIO 将返回一个例外:

EOSIO开发区块链DApp之智能合约第5张

5.查看投票结果

$ cleos get table election election candidate

EOSIO开发区块链DApp之智能合约第6张

如你所见,候选人“Donald J. Trump”的投票数为2.这意味着选举智能合约正在工作!

这就是EOS开发dapp的第二部分。安利个EOS智能合约与DApp开发入门:http://t.cn/Rgs1kbm

在下一部分中,我将创建一个Web应用程序,用于演示Web访问者和区块链之间的交互。

源代码在这里github repo

免责声明:文章转载自《EOSIO开发区块链DApp之智能合约》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇TorchVisionV0.9中引入的ML模型css3挖空文本特效下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【原】用Java编写第一个区块链(一)

  写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发。  【本文禁止任何形式的全文粘贴式转载,本文来自zacky31的随笔】 目标: 创建一个最基本的“区块链” 实现一个简单的挖矿系统 前提: 对面向对象编程有一定的基础 注意: 值得注意的是,这不会是一个完整的功能,恰恰相反,这是一个概念证明的实例,可以帮助您进一步了解区块链。 准备:   我将...

Fabric中多租户之间的数据隔离

如果我们的BaaS为某SaaS提供区块链服务,那么必然面对的就是每个租户的链上数据该如何隔离的问题。在Fabric中,一般来说我们有四种隔离方法,从软到硬分别是: 1.状态数据过滤隔离 我们知道状态数据都存储在一个KV数据库,而我们可以通过构建特定的前缀实现数据存入和数据查询时的过滤。也就是说在ChainCode中,只要是进行PutState时,Key必须...

标准化状态通道的架构与 Counterfactual

频繁的交易使的以太坊虚拟机变得越来越慢,交易费也越来越高。当下,大多数建立在以太坊上的应用都是通过更新链上合约的存储变量来实现,用户需要支付交易费并花一定时间等待区块确认。 当然,这也是低效的。为了使用应用,我们要求用户手动将数据库更新提交至世界上最安全的、分布式的、无需信任的。。。1999 年老式手机(译者注:意为当前的以太坊就像 1999 年的老式手...

【转载】比特币入门教程

作者: 阮一峰 原文地址:www.ruanyifeng.com/blog/2018/01/bitcoin-tutorial.html 推荐搜索上面链接,查看原文! 比特币(bitcoin)诞生于2008年的一篇论文。 一个署名为中本聪的人,提出了革命性的构想:让我们创造一种不受政府或其他任何人控制的货币!这个想法堪称疯狂:一串数字,背后没有任何资产支持,也...

公有链、私有链和联盟链

目前来说,根据不同的应用场景以及用户需求,区块链大致可以分为公有链(Public Blockchain)、私有链(Private Blockchain)以及联盟链(Consortium Blockchain)三大类。 其中去中心化程度最高的是公有链。这种以比特币以及以太坊为代表的公有区块链,不受第三方机构控制,世界上所有的人都可读取链上的数据记录、参与交...

信息摘要算法之七:SHA在区块链中的应用

最近几年比特币的火爆带动了人们对区块链技术的研究。当然我们在这里并不讨论区块链技术本身,而是讨论一下区块链中的SHA算法的应用。对于SHA系列算法我们已经在前面作了说明,在这里也不再重复。 1、区块链中的SHA 区块链中用到了SHA,可是究竟什么地方使用到了SHA算法呢?为了解决这个问题,我们必须先来了解下区块链的组成结构。每个区块都包括了一个被称为魔法数...