BCSkill (Block chain skill )
区块链中文技术社区

只讨论区块链底层技术
遵守一切相关法律政策!

How to pass struct to action

I have a simple struct with one member and want to pass this to an action.

struct field {
    bool is_private;
  };

  // @abi action
  // Create a new profile
  void create(const account_name& account, const field& first_name);

The .abi looks like this:

  "structs": [{
      "name": "field",
      "base": "",
      "fields": [{
          "name": "is_private",
          "type": "bool"
        }
      ]
    },{
      "name": "create",
      "base": "",
      "fields": [{
          "name": "account",
          "type": "name"
        },{
          "name": "first_name",
          "type": "field"
        }
      ]
    }
...

I tried a lot of different variations along the lines of cleos push action "contract" "create" '[acc_name, {"is_private": "true"}]' -p acc_name@active. But none of them seem to work. Are structs supported and if yes how do you pass the argument?

Thanks a lot!


Found the solution myself. You have to recreate the .abi structure in json:
cleos push action contract create '{"account":"acc_name","first_name":{"is_private":true"}}' -p acc_name@active

https://github.com/EOSIO/eos/issues/4914

Failed with error: Out of Range (8) read datastream of length 9 over by 1

麒麟测试网部署测试合约时出现一下错误

suroudeMacBook-Pro:contracts surou$ cleos -u http://api.kylin.eosbeijing.one:8880  get table cryptokylinq cryptokylinq results
2018-10-10T14:09:41.215 thread-0   main.cpp:3143                 main                 ] Failed with error: Out of Range (8)
read datastream of length 9 over by 1

开始演示步骤

开始部署合约中表的结构为

//@abi table results i64
    struct approval_info{
        account_name name;
        uint8_t iresult;
        uint64_t primary_key()const { return name; }
        EOSLIB_SERIALIZE(approval_info, (name)(iresult))
    };

    typedef eosio::multi_index<N(results),approval_info> result_table;

然后直接修改了 iresultstd::string

//@abi table results i64
    struct approval_info{
        account_name name;
        std::string iresult;
        uint64_t primary_key()const { return name; }
        EOSLIB_SERIALIZE(approval_info, (name)(iresult))
    };

    typedef eosio::multi_index<N(results),approval_info> result_table;

由于前面合约已部署,就像数据库中表字段的类型已经建好了,下次再部署时,导致表错乱,所以改个表名或者重新部署个账号测试把。等后面发现好的办法再跟帖

编译 eosio.cdt 出现error: redefinition of 'public_key'

先执行

rm -fr /usr/local/include/eosiolib

清理掉旧lib,再编译

sudo ./build.sh EOS

参考:GitHub

EOS 资源汇总

EOS 资源汇总

A curated list of EOS Ecosystem by SuperONE.



EOS 资源汇总。提交 PR 参考 contributing,提交 issue 点击 此处

中文 | English

EOS 主网

超级节点

GitHub

主网启动相关

主网启动状态

映射查询

区块浏览器

主网投票状态

主网投票

DevOps

文档

开发

安全

资源

社区

资讯

博客

空投

导航

下载

视频

工具

账号相关工具

浏览器插件

其他工具

EOS 钱包

硬件钱包

移动端

Web 钱包

浏览器插件钱包

开源钱包

交易所

中心化交易所

  • 畅思,专注 EOS 生态的区块链资产精品交易平台
  • 鲸交所,全球首个基于 EOS 主链开发、支持跨链的高流动性去中心化交易所
  • BigONE,BigONE 是一家数字资产交易及托管平台,帮助用户寻找全球优质区块链资产,提供便捷的交易服务,以顶尖的技术和安全控制流程保障用户数字资产安全,帮助用户进行资产管理。BigONE 团队汇集了来自世界各地的区块链专家、极客和爱好者
  • HADEX,火币自主数字资产交易所
  • EOSFINEX,全球首个高性能去中心化交易所
  • ZBG,Pos+Pow 交易挖矿,社区化自治的交易平台

去中心化交易所

  • Newdex,全球首家基于 EOS 的去中心化交易所,支持 SimpleWallet 协议
  • SouthEX,基于 EOS 的去中心化交易所
  • DEXEOS,全球首家基于 EOS 的去中心化交易所

Dapp

Dapp 展示

DApp 生态

  • EOS LIVE,EOS 社区首个产品与资讯聚合平台
  • AWOO!,允许用户合作完成共建更好的社会,目标是带来和平,繁荣和丰富
  • AZARUS,一个公平,可靠,透明的平台,用于玩令牌和下注。专门针对视频游戏行业而构建。
  • Billionaire Token,致力于成为首个在 EOS 区块链网络上运行的博彩娱乐场。代币通缩机制,通过分布式抽奖和智能合约每周销毁 XBL 代币。
  • Cards & Tokens.,可收藏的数字卡平台,用户可以上传内容并赚钱
  • Carmel.io,开源教育平台,可帮助有抱负和经验丰富的软件开发人员通过 token 化同行挑战来增长他们的技能并跟踪他们的成长
  • Chaince,专注 EOS 生态的区块链资产精品交易平台,支持糖果空投,主打严选项目,不收上币费
  • Chintai,Chintai 是一个由 EOS 节点候选者 EOS42 团队推出的 EOS 代币租赁平台,EOS 持币者就像是那些持有商业房产的投资客,而开发者是需要租用场地办公定期付租金的公司,双方各取所需,盘活了整个地产市场,而 Chintai 则是不收中介费的链家,这是一门相当有前景的生意
  • DEOS Games,赌场的边缘,赌场的平台
  • emanate,艺术家之间合作的音乐技术平台。 凭借智能合约,emanate 允许艺术家通过合作获利
  • EOS Bet,赌博系统,投资者可以支持房屋并获得股息
  • EOXCommerceA,分散的电子商务平台,允许使用基于 EOS 的加密货币和加密资产
  • EOSfinex,著名的交易所 Bitfinex 开发一个高性能、去中心化的交易所
  • EOS Gems,EOS 区块链上的收藏宝石游戏
  • Everipedia,一个众包的 wiki 平台,在线百科全书和知识库
  • HorusPay,分散的全球薪资门户网站,允许公司与国际薪资供应商交换私密的加密数据
  • HireVibes,一个众包型的去中心化求职招聘平台,解决中心化招聘平台收费高匹配度低的痛点
  • Insights Network,基于 EOS 的数据交易市场,用户可以直接出售他们的数据而不需要通过第三方
  • Karma,KARMA 旨在激励用户在世界上做得很好,并接受 KARMA 帮助人类
  • IRYO,去中心化的医疗数据,病人可以控制谁可以使用它并可以随身携带
  • Lab Ledger, A social media, crowdfunding website for scientists.
  • Onepay,帮助商家接收加密货币的支付钱包,传统的支付系统依靠中央银行和信贷机构,ONEPAY 的去中心化 POS 系统运行在 EOS 区块链上,只需付出一小部分成本即可闪电般交易
  • Oracle Chain,让世界与区块链互联
  • ONO,一个年轻人泛社交 App,定义了注意力价值,鼓励自由表达。目前社区已经初步形成
  • Plactal,Plactal 瞄准的是电子游戏市场。它通过收集每个玩家的信息做出分析,然后提供给游戏公司精准的广告投放信息
  • Scatter,用于保存身份和密钥安全的钱包。 项目的区块链部分是用于在应用程序和用户中建立信任
  • Sense,是一个 P2P 聊天机器人平台,便于任何两个用户通过各种不同的聊天工具实时对话,Sensay 利用人工智能匹配算法找出互相配对的用户
  • Seyara,一个开放的协议,以建立真正分散的点对点市场
  • SFEOS,玩家可以自己创建的,高沉浸式的体验游戏
  • Starteos,智能数字钱包,支持 EOS
  • Tokena,首个基于 EOS 的去中心化交易所
  • Trade Stuf,一个建立在 EOS 区块链上的高效,去中心化教育生态系统
  • TXT,支付观众的去中心化广告经济。 旨在激励观众观看所有人都获利的广告
  • Uncloak,将自己描述为世界上第一个基于区块链技术的网络威胁解决方案,通过一个完全自动化的区块链系统来解决网络威胁的弱点
  • Unico,去中心化数字收藏
  • Zimbra X,下一代 Zimbra 电子邮件和协作平台
  • EOS 超级矿工,EOS Asia 孵化的一款游戏:EOS 超级旷工,不发币,直接使用 EOS,奖池的 90% 左右的 EOS 全部返还给玩家,排行榜动态设计,保证后来的玩家的公平,总之我玩了几天感觉上手容易,既公平,也有趣味性,很快就上线,预约地址 http://eosminer.vip

参考:EOS dApp Ecosystem.

License

CC0

This list is released into the public domain.

SuperONE, robin

转载自 :https://github.com/superoneio/awesome-eos

eos系统合约介绍 — 提案合约eosio.msig (下)

简介

本篇将为大家介绍eosio.msig的源码实现,合约代码库详见:eosio.msig。eosio.msig主要有propose、approve、unapprove、cancel、exec、invalidate这几种方法,下面会详细逐一介绍每种方法的功能和实现细节。

主要合约方法

eosio.msig合约,在eosio.msig.hpp头文件中,主要定义了以下六个合约方法:

  • propose:提出提案
  • approve:通过提案
  • unapprove:不通过提案
  • cancel:取消提案
  • exec:执行提案
  • invalidate:撤回对之前所有该账户通过、但未被最终执行的提案的通过授权

eosio.msig合约头文件

namespace eosio {

   class multisig : public contract {
      public:
         multisig( account_name self ):contract(self){}

         void propose();
         void approve( account_name proposer, name proposal_name, permission_level level );
         void unapprove( account_name proposer, name proposal_name, permission_level level );
         void cancel( account_name proposer, name proposal_name, account_name canceler );
         void exec( account_name proposer, name proposal_name, account_name executer );
         void invalidate( account_name account );

propose方法

propose方法主要功能是提出提案,对应上篇提到的 cleos multisig propose 命令,传参如下:

  • proposer:提案账户
  • proposal_name:提案名
  • requested:提案通过所需权限
  • trx:提案具体执行的交易内容

为了节省资源开销,propose方法并不会根据 cleos multisig propose 传入的参数一一做解析,而是直接解析input data

/*
propose function manually parses input data (instead of taking parsed arguments from dispatcher)
because parsing data in the dispatcher uses too much CPU in case if proposed transaction is big

If we use dispatcher the function signature should be:

void multisig::propose( account_name proposer,
                        name proposal_name,
                        vector<permission_level> requested,
                        transaction  trx)
*/

void multisig::propose() {
   constexpr size_t max_stack_buffer_size = 512;
   size_t size = action_data_size();
   char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) );
   read_action_data( buffer, size );

之后,会做一系列前置检验工作:proposer提案账户授权是否正确、交易是否超时、propose_name是否存在、提案通过所需权限是否正确等

require_auth( proposer );
   eosio_assert( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" );
   //eosio_assert( trx_header.actions.size() > 0, "transaction must have at least one action" );

   proposals proptable( _self, proposer );
   eosio_assert( proptable.find( proposal_name ) == proptable.end(), "proposal with the same name exists" );

   bytes packed_requested = pack(requested);
   auto res = ::check_transaction_authorization( buffer+trx_pos, size-trx_pos,
                                                 (const char*)0, 0,
                                                 packed_requested.data(), packed_requested.size()
                                               );
   eosio_assert( res > 0, "transaction authorization failed" );

之后,将提案和提案合约的内容存表,将提案通过所需的权限存入requested_approvals表中,我们上篇文章所提到 cleos get table eosio.msig <proposer account> approvals 命令查询的就是这张表

proptable.emplace( proposer, [&]( auto& prop ) {
      prop.proposal_name       = proposal_name;
      prop.packed_transaction  = bytes( buffer+trx_pos, buffer+size );
   });

   approvals apptable(  _self, proposer );
   apptable.emplace( proposer, [&]( auto& a ) {
      a.proposal_name       = proposal_name;
      a.requested_approvals.reserve( requested.size() );
      for ( auto& level : requested ) {
         a.requested_approvals.push_back( approval{ level, time_point{ microseconds{0} } } );
      }
   });

approve方法

approve方法的主要功能是通过提案,对应上篇提到的 cleos multisig approve 命令,传参如下

  • proposer:提案人
  • proposal_name:提案名
  • permissions:使用哪个权限批准这个提案

首先,系统会查找提案合约内容,查找 requested_approvals 表中需要通过的权限中,是否有和传入permission匹配项。若有匹配项,将此权限加入 provided_approvals 表,即表示该权限通过此提案,并从 requested_approvals 表中移除该权限。

void multisig::approve( account_name proposer, name proposal_name, permission_level level ) {
   require_auth( level );

   approvals apptable(  _self, proposer );
   auto apps_it = apptable.find( proposal_name );
   if ( apps_it != apptable.end() ) {
      auto itr = std::find_if( apps_it->requested_approvals.begin(), apps_it->requested_approvals.end(), [&](const approval& a) { return a.level == level; } );
      eosio_assert( itr != apps_it->requested_approvals.end(), "approval is not on the list of requested approvals" );

      apptable.modify( apps_it, proposer, [&]( auto& a ) {
            a.provided_approvals.push_back( approval{ level, current_time_point() } );
            a.requested_approvals.erase( itr );
         });
   } else {
      old_approvals old_apptable(  _self, proposer );
      auto& apps = old_apptable.get( proposal_name, "proposal not found" );

      auto itr = std::find( apps.requested_approvals.begin(), apps.requested_approvals.end(), level );
      eosio_assert( itr != apps.requested_approvals.end(), "approval is not on the list of requested approvals" );

      old_apptable.modify( apps, proposer, [&]( auto& a ) {
            a.provided_approvals.push_back( level );
            a.requested_approvals.erase( itr );
         });
   }
}

unapprove方法

unapprove方法的主要功能是不通过提案,对应上篇提到的 cleos multisig unapprove 命令,传参如下:

  • proposer:提案人
  • proposal_name:提案名
  • permissions:使用哪个权限拒绝这个提案

首先,系统会查找提案合约内容,查找 provided_approvals 表中通过的权限中,是否有和传入permission匹配项。若有匹配项,将此权限加入requested_approvals 表,即表示该权限还没通过此提案,并从 provided_approvals 表中移除该权限。

void multisig::unapprove( account_name proposer, name proposal_name, permission_level level ) {
   require_auth( level );

   approvals apptable(  _self, proposer );
   auto apps_it = apptable.find( proposal_name );
   if ( apps_it != apptable.end() ) {
      auto itr = std::find_if( apps_it->provided_approvals.begin(), apps_it->provided_approvals.end(), [&](const approval& a) { return a.level == level; } );
      eosio_assert( itr != apps_it->provided_approvals.end(), "no approval previously granted" );
      apptable.modify( apps_it, proposer, [&]( auto& a ) {
            a.requested_approvals.push_back( approval{ level, current_time_point() } );
            a.provided_approvals.erase( itr );
         });
   } else {
      old_approvals old_apptable(  _self, proposer );
      auto& apps = old_apptable.get( proposal_name, "proposal not found" );
      auto itr = std::find( apps.provided_approvals.begin(), apps.provided_approvals.end(), level );
      eosio_assert( itr != apps.provided_approvals.end(), "no approval previously granted" );
      old_apptable.modify( apps, proposer, [&]( auto& a ) {
            a.requested_approvals.push_back( level );
            a.provided_approvals.erase( itr );
         });
   }
}

cancel方法

cancel方法的主要功能是取消提案,对应上篇提到的 cleos multisig cancel 命令,传参如下:

  • proposer:提案账户
  • proposal_name:提案名
  • canceler:取消账户

首先,先查找表获取提案内容。如果canceler账户和提案账户不同,则在提案交易过期之前,canceler都不能取消提案。若能取消,将提案从表中移除。

void multisig::cancel( account_name proposer, name proposal_name, account_name canceler ) {
   require_auth( canceler );

   proposals proptable( _self, proposer );
   auto& prop = proptable.get( proposal_name, "proposal not found" );

   if( canceler != proposer ) {
      eosio_assert( unpack<transaction_header>( prop.packed_transaction ).expiration < eosio::time_point_sec(current_time_point()), "cannot cancel until expiration" );
   }
   proptable.erase(prop);

   //remove from new table
   approvals apptable(  _self, proposer );
   auto apps_it = apptable.find( proposal_name );
   if ( apps_it != apptable.end() ) {
      apptable.erase(apps_it);
   } else {
      old_approvals old_apptable(  _self, proposer );
      auto apps_it = old_apptable.find( proposal_name );
      eosio_assert( apps_it != old_apptable.end(), "proposal not found" );
      old_apptable.erase(apps_it);
   }
}

exec方法

exec方法的主要功能是执行提案,对应上篇提到的 cleos multisig exec 命令,传参如下:

  • proposer:提案账户
  • proposal_name:提案名
  • executer:执行账户
void multisig::exec( account_name proposer, name proposal_name, account_name executer ) {
   require_auth( executer );

   proposals proptable( _self, proposer );
   auto& prop = proptable.get( proposal_name, "proposal not found" );
   transaction_header trx_header;
   datastream<const char*> ds( prop.packed_transaction.data(), prop.packed_transaction.size() );
   ds >> trx_header;
   //首先,需要做前置检查,检查交易是否过期
   eosio_assert( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" );

   approvals apptable(  _self, proposer );
   auto apps_it = apptable.find( proposal_name );
   vector<permission_level> approvals;
   //然后,查 provided_approvals 表获取通过提案交易的权限们,对比 inv_table 表,如果权限不在 inv_table 表中或者 last_invalidation_time 
   //已经小于当前时间,代表权限有效,放入approvals表中。inv_table 表的用途在下一个invalidate方法中介绍
   invalidations inv_table( _self, _self );
   if ( apps_it != apptable.end() ) {
      approvals.reserve( apps_it->provided_approvals.size() );
      for ( auto& p : apps_it->provided_approvals ) {
         auto it = inv_table.find( p.level.actor );
         if ( it == inv_table.end() || it->last_invalidation_time < p.time ) {
            approvals.push_back(p.level);
         }
      }
      apptable.erase(apps_it);
   } else {
      old_approvals old_apptable(  _self, proposer );
      auto& apps = old_apptable.get( proposal_name, "proposal not found" );
      for ( auto& level : apps.provided_approvals ) {
         auto it = inv_table.find( level.actor );
         if ( it == inv_table.end() ) {
            approvals.push_back( level );
         }
      }
      old_apptable.erase(apps);
   }
   //最后,执行提案。如果交易执行权限检验无误,会发起一个defer延迟合约,去执行提案交易。如果执行成功,
   //`cleos get actions <executer account>` 会产生两条actions,一条是exec的交易,一条是提案执行的交易。
   bytes packed_provided_approvals = pack(approvals);
   auto res = ::check_transaction_authorization( prop.packed_transaction.data(), prop.packed_transaction.size(),
                                                 (const char*)0, 0,
                                                 packed_provided_approvals.data(), packed_provided_approvals.size()
                                                 );
   eosio_assert( res > 0, "transaction authorization failed" );

   send_deferred( (uint128_t(proposer) << 64) | proposal_name, executer, prop.packed_transaction.data(), prop.packed_transaction.size() );

   proptable.erase(prop);
}

invalidate方法

invalidate方法的主要功能是:如果account之前通过的提案还未执行,就可以使用该方法将提案一键设置为无效。这个方法主要是解决:账户权限变更时,之前通过但未执行的提案一旦执行会盗取账户权限的问题,详见issue。该方法传参如下:

  • account:提案的批准账户

该功能的实现非常简单,首先,inv_table 是用来存放权限的,它的两个字段 account 和last_invalidation_time 分别是账户名和账户权限最近失效时间。last_invalidation_time 时间之前,account的提案批准权限都不可用,在该时间之后account的提案批准权限才能生效。

因此,如果想使account之前审批通过的所有提案都失效的话,就将 last_invalidation_time 设置为当前时间即可。exec方法在执行之前会检查 inv_table,则包含在 inv_table 中的account,即便批准了该提案,该批准也会作废

void multisig::invalidate( account_name account ) {
   require_auth( account );
   invalidations inv_table( _self, _self );
   auto it = inv_table.find( account );
   if ( it == inv_table.end() ) {
      inv_table.emplace( account, [&](auto& i) {
            i.account = account;
            i.last_invalidation_time = current_time_point();
         });
   } else {
      inv_table.modify( it, account, [&](auto& i) {
            i.last_invalidation_time = current_time_point();
         });
   }
}

转载自简书