实时滚动新闻

EOS部署、智能合约应用开发和代币映射

2018-05-28 10:59:00    轻松万里行        点击:

  距离EOS主网上线还有不到一周,现在持有EOS的人请注意:如果不在交易所的,一定要去注册下。近日,区块链领域专家谷老师做了关于EOS部署、智能合约应用开发和代币映射内容的技术分享,引起了众多同行的关注。

\

  目前最大的EOS应用是区块链百科(https://everipedia.org/),已获得7500万美元的融资,它对标的是维基百科。这个应用的大概规则是:比如当你要编辑一个词条时,你需要抵押自己的Token,然后每天会产生限量token激励,社区里的事情都要进行投票,进行自治,大于75%的投票,才可以修改词条。这是因为它的内容是存放在IPFS里。当然,还有很多EOS应用,我只挑了一个典型的。

  EOS如何部署私有环境?

  https://github.com/EOSIO/eos/wiki

  编译命令:https://github.com/EOSIO/eos/wiki/Local-Environment#2-building-eosio

\

  EOS网络是由无数个nodes组成的,提供单独keosd 钱包节点,可以单独下。相对而言,以太坊节点会自动同步数据,会很慢。

  启动EOS节点命令:./nodeos -e -p eosio --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin

\

  使用cleos创建钱包及账号(https://github.com/EOSIO/eos/wiki/Programs-&-Tools#cleos),这里要注意EOS钱包和以太坊钱包的区别:EOS主要管理私钥,不是一个离线账号,是建立在EOS节点上注册后的账号。

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ wallet unlock

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ wallet list

  管理2组账号,第一组账号是eosio,其他所有eos账号都是在第一个eosio上派生出来的。

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ create key

  我们先来创建私钥:

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ wallet import 私钥

  现在就多了一组账号。

  然后开始创建EOS上的账户。

  以太坊的账号是一个40字符的字符串,很难被记住。EOS权限分组,owner是最高权限,active 可以管理账号的资产。

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ create account eosio 唯一名字(可以抢注) OwnerKey ActiveKey

  这样你的唯一名字就注册到EOS网络上了,别人可以直接给你这个名字的账号里打钱或者各种操作,以上操作意味着创建账户和管理私钥的内容就完成了。

  接下来就是创建合约,先来讲2个案例:

  第一个案例:飞行宝

\

  飞行宝的具体逻辑是:用户要坐飞机,在飞行前,用户买了哪一期的哪一个航班,EOS提供了一个多索引的数据表结构叫multi_Index,

  uint64_t term_Id; 每一天开一期

  account_name 就是我们刚刚在eos上注册的唯一用户名,代表购买者账号

  uint64_t content; 可以留言

  account_name get_poster() const { return account }

  fmulti_index多索引,类似一个mysql一个表名,第一个字段是表名,后面是列,就是定义了一个数据表。

  总共有4个操作:第一个操作是购买某一天的航班,购买就是一个添加数据的过程;第二操作是获取购买的情况;第三个操作是查询你的所有购买记录,返回一个数组;第四个操作是修改操作。

  我们来实际操作下:

  eosiocpp -o flybaby.wast flybaby.cpp

  生成一个 webassembly 文件,这是ABI文件(现在EOS网络还有一些bug,要手动改下某几处ABI文件才可以运行)。

  现在开始部署合约

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ set contract 唯一名字 flybaby

\

  和以太坊有区别的是EOS可以修改智能合约。

  接下来是调用方法

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ push action 唯一名字 create '[1, 1, "唯一名字", 3000, "备注"]' -p 唯一名字

  说明调用成功

  cleos -u http://47.98.56.32:8888/ --wallet-url http://47.98.56.32:9999/ get table 唯一名字 唯一名字 fdata

  返回一个JSON数据,用一个新账号再来买一个。返回2个飞行宝购买记录,说明成功。get 方法是获取某一天的航班,list方法返回我所有的飞行宝购买记录。

  合约源码:

  flybaby.cpp

  #include

  #include

  using namespace eosio;

  using std::string;

  class flybaby : public eosio::contract {

  public:

  //self 代表合约拥有者账号.

  flybaby( account_name self ):contract(self){}

  /// @abi table

  struct record {

  uint64_t term_id; //飞行宝期数+航班ID作为主键

  account_name customer; //购买者账号

  uint64_t amount; //购买数量

  string content; //留言

  //客户在当期仅能买一次某航班,但可以买多个不同航班.

  uint64_t primary_key()const { return term_id; }

  //根据客户筛选出他购买的航班列表.

  account_name get_poster() const { return customer; }

  EOSLIB_SERIALIZE(record, (term_id)(customer)(amount)(content))

  };

  typedef eosio::multi_index

  indexed_by

  const_mem_fun> > records;

  using contract::contract;

  /// @abi action

  void create(uint64_t term,uint64_t id,account_name user,uint64_t amount, string content) {

  require_auth( user ); //验证权限,只能用自己的账号给你自己买.

  records datable( _self, _self); //定义数据库对象,数据库属于合约创建者,并且都存在一个表中.

  //简化仅表达意思,没做校验,注意运算符优先级.

  uint64_t term_id = (term << 32) + id;

  datable.emplace(user, [&]( record & d){

  eosio::print("ok this is lamda");

  //d.term_id = datable.available_primary_key();

  d.term_id = term_id;

  d.customer = user;

  d.amount = amount;

  d.content = content;

  eosio::print("update");

  });//数据库内容创建

  }

  void get(uint64_t term,uint64_t id,account_name user) {

  require_auth(user);

  records datable(_self, _self);

  uint64_t term_id = (term << 32) + id;

  auto info = datable.find(term_id);

  eosio::print("Term_id: ", info->term_id,

  " Customer: ", name{info->customer},

  " Amount: ", info->amount,

  " Content: ", info->content.c_str());

  }

  void list(account_name user) {

  require_auth(user);

  records datable(_self, _self);

  auto poster_index = datable.template get_index();

  auto pos = poster_index.find( user );

  for (; pos != poster_index.end(); pos++)

  {

  eosio::print("Term_id: ", pos->term_id,

  " Customer: ", name{pos->customer},

  " Amount: ", pos->amount,

  " Content: ", pos->content.c_str());

  eosio::print("||");

  }

  }

  void change(account_name user, uint64_t term, uint64_t id, string content)

  {

  require_auth(user);

  records datable( _self, _self);

  uint64_t term_id = (term << 32) + id;

  auto info = datable.find(term_id);

  eosio_assert(info->customer == user, "not your account");

  //此处payer不是user

  datable.modify(info, _self, [&](auto& p){

  if (content != "")

  p.content = content;

  });

  }

  void dele(account_name user, uint64_t term, uint64_t id)

  {

  require_auth(user);

  records datable( _self, _self);

  uint64_t term_id = (term << 32) + id;

  auto info = datable.find(term_id);

  eosio::print(info->content.c_str());

  eosio_assert(info->customer == user, "not your account");

  datable.erase(info);

  }

  };

  EOSIO_ABI(flybaby, (create)(get)(list)(change)(dele))

  接下来讲解 Token 的合约

  EOS上没有ERC20的协议,来看下逻辑:

\

  currency_stats代表一个资产的结构体,有资产的代号、名称;

  max_supply 最大发行量;

  issuer 是代币的发行者;

\

  填写好Token的名字、代号、发行量,做好准备工作。

  require_auth(st.issuer) 只有发行者可以修改当前的发行量;

  token::issue 方法就是发布出去;

  token::transfer 就是转账功能;

  就是对余额进行增加、减少的处理。

  合约源码:

  token.cpp

  /**

  * @file

  * @copyright defined in eos/LICENSE.txt

  */

  #include "mydogcon.hpp"

  namespace eosio {

  void token::create( account_name issuer,

  asset maximum_supply )

  {

  require_auth( _self );

  auto sym = maximum_supply.symbol;

  eosio_assert( sym.is_valid(), "invalid symbol name" );

  eosio_assert( maximum_supply.is_valid(), "invalid supply");

  eosio_assert( maximum_supply.amount > 0, "max-supply must be positive");

  stats statstable( _self, sym.name() );

  auto existing = statstable.find( sym.name() );

  eosio_assert( existing == statstable.end(), "token with symbol already exists" );

  statstable.emplace( _self, [&]( auto& s ) {

  s.supply.symbol = maximum_supply.symbol;

  s.max_supply = maximum_supply;

  s.issuer = issuer;

  });

  }

  void token::issue( account_name to, asset quantity, string memo )

  {

  auto sym = quantity.symbol;

  eosio_assert( sym.is_valid(), "invalid symbol name" );

  auto sym_name = sym.name();

  stats statstable( _self, sym_name );

  auto existing = statstable.find( sym_name );

  eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" );

  const auto& st = *existing;

  require_auth( st.issuer );

  eosio_assert( quantity.is_valid(), "invalid quantity" );

  eosio_assert( quantity.amount > 0, "must issue positive quantity" );

  eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );

  eosio_assert( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply");

  statstable.modify( st, 0, [&]( auto& s ) {

  s.supply += quantity;

  });

  add_balance( st.issuer, quantity, st, st.issuer );

  if( to != st.issuer ) {

  SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} );

  }

  }

  void token::transfer( account_name from,

  account_name to,

  asset quantity,

  string /*memo*/ )

  {

  eosio_assert( from != to, "cannot transfer to self" );

  require_auth( from );

  eosio_assert( is_account( to ), "to account does not exist");

  auto sym = quantity.symbol.name();

  stats statstable( _self, sym );

  const auto& st = statstable.get( sym );

  require_recipient( from );

  require_recipient( to );

  eosio_assert( quantity.is_valid(), "invalid quantity" );

  eosio_assert( quantity.amount > 0, "must transfer positive quantity" );

  eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );

  sub_balance( from, quantity, st );

  add_balance( to, quantity, st, from );

  }

  void token::sub_balance( account_name owner, asset value, const currency_stats& st ) {

  accounts from_acnts( _self, owner );

  const auto& from = from_acnts.get( value.symbol.name() );

  eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" );

  if( from.balance.amount == value.amount ) {

  from_acnts.erase( from );

  } else {

  from_acnts.modify( from, owner, [&]( auto& a ) {

  a.balance -= value;

  });

  }

  }

  void token::add_balance( account_name owner, asset value, const currency_stats& st, account_name ram_payer )

  {

  accounts to_acnts( _self, owner );

  auto to = to_acnts.find( value.symbol.name() );

  if( to == to_acnts.end() ) {

  to_acnts.emplace( ram_payer, [&]( auto& a ){

  a.balance = value;

  });

  } else {

  to_acnts.modify( to, 0, [&]( auto& a ) {

  a.balance += value;

  });

  }

  }

  } /// namespace eosio

  EOSIO_ABI( eosio::token, (create)(issue)(transfer) )

  token.hpp

  /**

  * @file

  * @copyright defined in eos/LICENSE.txt

  */

  #pragma once

  #include

  #include

  #include

  namespace eosiosystem {

  class system_contract;

  }

  namespace eosio {

  using std::string;

  class token : public contract {

  public:

  token( account_name self ):contract(self){}

  void create( account_name issuer,

  asset maximum_supply);

  void issue( account_name to, asset quantity, string memo );

  void transfer( account_name from,

  account_name to,

  asset quantity,

  string memo );

  private:

  friend eosiosystem::system_contract;

  inline asset get_supply( symbol_name sym )const;

  inline asset get_balance( account_name owner, symbol_name sym )const;

  private:

  struct account {

  asset balance;

  uint64_t primary_key()const { return balance.symbol.name(); }

  };

  struct currency_stats {

  asset supply;

  asset max_supply;

  account_name issuer;

  uint64_t primary_key()const { return supply.symbol.name(); }

  };

  typedef eosio::multi_index accounts;

  typedef eosio::multi_index stats;

  void sub_balance( account_name owner, asset value, const currency_stats& st );

  void add_balance( account_name owner, asset value, const currency_stats& st,

  account_name ram_payer );

  public:

  struct transfer_args {

  account_name from;

  account_name to;

  asset quantity;

  string memo;

  };

  };

  asset token::get_supply( symbol_name sym )const

  {

  stats statstable( _self, sym );

  const auto& st = statstable.get( sym );

  return st.supply;

  }

  asset token::get_balance( account_name owner, symbol_name sym )const

  {

  accounts accountstable( _self, owner );

  const auto& ac = accountstable.get( sym );

  return ac.balance;

  }

  } /// namespace eosio

  提问环节

  1:讲讲你的EOS信仰

  谷老师:我一般对EOS失去信心的时候,我就会去reddit看下EOS上朋友们的留言,上面的消息是很及时,而且上面的朋友特别友好,给你不割肉的动力。比如:big news is coming soon……winter is coming……Image you are one of them……The Dawn is coming……

  每当我难受的时候,我就来这里,我的信仰就是来自这里。

  2:主链上线时间有没有风险?

  谷老师:现在EOS 1.0 上线已经完成 94%,EOS还是可以的,有一定风险会延迟。现在讲一下EOS百万TPS的梗:它一共21个超级节点,有点类似我们在用负载均衡,比如10台机器,轮训来分发流量,如果当前有1万交易,会分到某个节点上,由于单台服务器节点很高,能一次性处理。

  另外我推荐ONO这个区块链应用,未来随着区块链的升级换代,提升基础设施,也许我们后端开发就不像现在这样去买一台云服务器,而未来所有的后端就是一个区块链,所有应用都会直接构建到区块链上,像聊天、打车就直接构建在像这样的EOS区块链上,打车的结算公开在区块链上,就不存在杀熟的问题。甚至公司的形式也会发生变化,而是由使用者来决定。未来区块链就不只是炒币的功能。

  3:如果一个用户开发了一个很好的应用,大户如果抄袭,大户会不会抢走EOS运行的资源?

  谷老师:根据你抵押的EOS份额来租用算力。这是一个商业逻辑,如果你的应用很火,就会有资本投你,算力不太可能被垄断。

  谷老师在最后还讲到,伴随夏季的来临,航班延误或取消都进入了高发期。而航空延误险则是很多常旅客的必备,而全球区块链互助社区HMS,其基于区块链技术和底层的风险保障逻辑,设计出的全自动的智能型全球航空飞行延误互助保障合约——“飞行宝”现在已完成首例赔付。

  一直以来,区块链技术和基于区块链的项目,因为与现实世界脱节而蒙上了神秘的面纱。与此同时,底层技术不够成熟、缺乏智能合约公链平台,影响了区块链技术的发展以及应用化的过程。HMS一直在探索区块链技术和互助业务相结合的创新,为更多的现实场景提供服务,对促进区块链世界与现实世界的进一步联动有深刻意义,他非常看好这一应用。

相关新闻:

下一篇:最后一页
中国质量万里行 | 关于我们 | 联系我们 | 服务声明 | 人才招聘
Copyright © 2002 - 2018 中国质量万里行
京公网安备11010502034432号     京ICP备13012862号