您正在查看: Surou 发布的文章

编译 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();
         });
   }
}

转载自简书

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

简介

本篇将为大家介绍eos另一个系统合约eos.msig的主要功能和源码实现细节。eos.msig是eos的提案合约,同样也是cleos multisig命令调用的系统合约,可用于提案、通过/不通提案、执行多重签名交易等功能。由于涉及内容较多,介绍将分为上下两篇,上篇将围绕eos账户权限、cleos multisig命令的使用这几个方面进行介绍,下篇则会为大家介绍eosio.msig的源码实现

Eos账户权限

回顾一下之前的文章,一个账户最基本的权限owner和active是由公私钥对控制的,然而,eos丰富的权限控制方式,还允许我们将一个账户的权限,下放给其他的账户。比如下面的经典例子:
账户popo的权限情况

permissio account weight threshold
owner 2
@user1 1
@user2 1
active 1
@user1 1
@user2 1

我们将一步一步,通过命令行操作的方式来为大家介绍eos权限的应用。

1.我们分别创建三个账户popo11111111、zoin11111111、zoin22222222,每个账户使用不同的公私钥对。
分别创建6对公私钥,分别用于三个账号的owner和active权限

cleos create key --to-console

| 账号 | 权限|公钥 |私钥 |
| ------------ | ------------ | ------------ |
| popo11111111 | owner | EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB | 5JAxr3bM6DwwtcKJ7aVydpoaSA2oyiZ94PjqTpW6uXDZ41VuK22|
| popo11111111 | active | EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T |5KRCeqsHAx1UNTtz7BH5N4SSMe75XMCj3j93TqQRDrYCwbjccoP |
| zoin11111111 | owner | EOS5N3qMPXjtwZpMyPeiYXSmBQbr7Lt5Ro2W8pLqyAzFYQPknoUvZ |5KWYcdZcJ1E8mWtg1Qoq5s1fYXJxMQkLupozfZEUEiu6vn6QNzx |
| zoin11111111 | active | EOS6BAfK8mZZjMaa74zxkT3evWEtWo4AnRQYmnpGWkNJYKVjcrpao | 5Jwy6VbCwpkmczjYgMNVtr9Nd77aenZcPE8DtvPwtYqztbgMzu4|
| zoin22222222 | owner | EOS6hBy5yioHpcH4SxSe91aH8vCGAhhEifKtp1jZEy7PS2rhJFSER |5Hz3u44Avpf4NCVDQdwZGSVXpbpEdRFczo2Wm9FC14pqcx8mUwM |
| zoin22222222 | active | EOS5TeY2C9bdewrbS58SZnrp5azF5Cq7AXraNJihxaW4hbGeWSaeE |5JFoGdAc6zPG9KdHCHPHFL5XbpEnFmDq61y53Bw3Hm3VuFy7Stk |

2.下面开始创建三个账号

cleos system newaccount 已有账号 将要创建的账号 ownerkey  activekey  --stake-net '0.1 EOS' --stake-cpu '0.1 EOS'  --buy-ram-kbytes 4000

利用我们上面文章《以传统的WEB开发方式,来举例理解Dapp开发》中已经在麒麟测试网创建的账号cryptokylinq,并在麒麟测试网来创建其他账号。

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq popo11111111 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB  EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T  --stake-net '0.1 EOS' --stake-cpu '0.1 EOS'  --buy-ram-kbytes 4000
executed transaction: ada14edaa2dc356f02f8f19515f3227669887a5a840601d28f8d59238e1c7890  336 bytes  4284 us
#         eosio <= eosio::newaccount            {"creator":"cryptokylinq","name":"popo11111111","owner":{"threshold":1,"keys":[{"key":"EOS81WjiHefR6...
#         eosio <= eosio::buyrambytes           {"payer":"cryptokylinq","receiver":"popo11111111","bytes":4096000}
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8497 EOS","memo":"buy ram"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8497 EOS","memo":"buy ram"}
#     eosio.ram <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8497 EOS","memo":"buy ram"}
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5018 EOS","memo":"ram fee"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5018 EOS","memo":"ram fee"}
#  eosio.ramfee <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5018 EOS","memo":"ram fee"}
#         eosio <= eosio::delegatebw            {"from":"cryptokylinq","receiver":"popo11111111","stake_net_quantity":"0.1000 EOS","stake_cpu_quanti...
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
#   eosio.stake <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
2018-09-25T04:07:44.999 thread-0   main.cpp:458                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq zoin11111111 EOS5N3qMPXjtwZpMyPeiYXSmBQbr7Lt5Ro2W8pLqyAzFYQPknoUvZ  EOS6BAfK8mZZjMaa74zxkT3evWEtWo4AnRQYmnpGWkNJYKVjcrpao  --stake-net '0.1 EOS' --stake-cpu '0.1 EOS'  --buy-ram-kbytes 4000
executed transaction: daf4b102f68d7161022c0ac8635d91137a0d2d24072d49fdad13a608e2e03072  336 bytes  5102 us
#         eosio <= eosio::newaccount            {"creator":"cryptokylinq","name":"zoin11111111","owner":{"threshold":1,"keys":[{"key":"EOS5N3qMPXjtw...
#         eosio <= eosio::buyrambytes           {"payer":"cryptokylinq","receiver":"zoin11111111","bytes":4096000}
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8589 EOS","memo":"buy ram"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8589 EOS","memo":"buy ram"}
#     eosio.ram <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8589 EOS","memo":"buy ram"}
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
#  eosio.ramfee <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
#         eosio <= eosio::delegatebw            {"from":"cryptokylinq","receiver":"zoin11111111","stake_net_quantity":"0.1000 EOS","stake_cpu_quanti...
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
#   eosio.stake <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
2018-09-25T04:11:22.091 thread-0   main.cpp:458                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq zoin22222222 EOS6hBy5yioHpcH4SxSe91aH8vCGAhhEifKtp1jZEy7PS2rhJFSER  EOS5TeY2C9bdewrbS58SZnrp5azF5Cq7AXraNJihxaW4hbGeWSaeE  --stake-net '0.1 EOS' --stake-cpu '0.1 EOS'  --buy-ram-kbytes 4000
executed transaction: 7b184ccebaeb2cd2b6cece49ec46abd86b20a1d20b29722d21029dd1abc958f0  336 bytes  2667 us
#         eosio <= eosio::newaccount            {"creator":"cryptokylinq","name":"zoin22222222","owner":{"threshold":1,"keys":[{"key":"EOS6hBy5yioHp...
#         eosio <= eosio::buyrambytes           {"payer":"cryptokylinq","receiver":"zoin22222222","bytes":4096000}
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8723 EOS","memo":"buy ram"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8723 EOS","memo":"buy ram"}
#     eosio.ram <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ram","quantity":"99.8723 EOS","memo":"buy ram"}
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
#  eosio.ramfee <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.ramfee","quantity":"0.5019 EOS","memo":"ram fee"}
#         eosio <= eosio::delegatebw            {"from":"cryptokylinq","receiver":"zoin22222222","stake_net_quantity":"0.1000 EOS","stake_cpu_quanti...
#   eosio.token <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
#  cryptokylinq <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
#   eosio.stake <= eosio.token::transfer        {"from":"cryptokylinq","to":"eosio.stake","quantity":"0.2000 EOS","memo":"stake bandwidth"}
2018-09-25T04:13:52.457 thread-0   main.cpp:458                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

3.将popo11111111的owner权限交出,由zoin11111111和zoin22222222的owner权限控制。每个权限的权重weight是1,而门槛threshold是2,即使用popo11111111的owner权限发送交易,需要zoin11111111和zoin22222222进行多重签名才行
先将popo11111111的owner私钥导入钱包

suroudeMacBook-Pro:~ surou$ cleos wallet import
private key: imported private key for: EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB

查看下popo11111111信息

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account popo11111111
permissions: 
     owner     1:    1 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB
        active     1:    1 EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T

将popo11111111的owner权限交出

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com set account permission popo11111111 owner '{"threshold":2, "keys":[{"key": "EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB"}], "accounts": [{"permission": {"actor": "zoin11111111", "permission": "owner"}, "weight": 1}, {"permission": {"actor": "zoin22222222", "permission": "owner"}, "weight": 1}]}' -p popo11111111@owner
executed transaction: 38317f76ad1eb90601ad9bd2c6720e322196aebbb8bed5afacfd4f7c5098b111  200 bytes  759 us
#         eosio <= eosio::updateauth            {"account":"popo11111111","permission":"owner","parent":"","auth":{"threshold":2,"keys":[{"key":"EOS...

再次查看popo11111111账户

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account popo11111111
permissions: 
     owner     2:    60450 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB1 zoin11111111@owner, 1 zoin22222222@owner, 
        active     1:    1 EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T

已将权限owner转交给了 zoin11111111@owner, 1 zoin22222222@owner

4.将popo11111111的active权限交出,由zoin11111111和zoin22222222的active权限控制。每个权限的权重weight是1,而门槛threshold是1,即使用popo11111111的active权限发送交易,zoin11111111和zoin22222222任意一个账户签名即可
先将popo11111111的owner私钥导入钱包

suroudeMacBook-Pro:~ surou$ cleos wallet import
private key: imported private key for: EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T

将popo11111111的active权限交出

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com set account permission popo11111111 active '{"threshold":1, "keys":[{"key": "EOS6L7pr3AaKekTs1dbratDq1PutoSdmBWJFwbLcStsnKBbJtNUws"}], "accounts": [{"permission": {"actor": "zoin11111111", "permission": "active"}, "weight": 1}, {"permission": {"actor": "zoin22222222", "permission": "active"}, "weight": 1}]}' -p popo11111111@active
executed transaction: c51dede340204a6561b9ad511efcf1f194075319a97f54e7fce1dbee8b20eb18  200 bytes  748 us
#         eosio <= eosio::updateauth            {"account":"popo11111111","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[{"key...

再次查看popo11111111账户

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account popo11111111
permissions: 
     owner     2:    60450 EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB1 zoin11111111@owner, 1 zoin22222222@owner, 
        active     1:    31778 EOS6L7pr3AaKekTs1dbratDq1PutoSdmBWJFwbLcStsnKBbJtNUws1 zoin11111111@active, 1 zoin22222222@active, 

已经权限active转交给1 zoin11111111@active, 1 zoin22222222@active

cleos multisig命令

EOS账户这一节,我们将popo11111111账户的owner和active权限交给了zoin11111111和zoin22222222账户,则popo11111111账户原来的公私钥对就失效了,交易的发送需要zoin11111111和zoin22222222账户授权。

额外提一句,主网启动后,超级节点们会将eosio账户的权限交给eosio.prods账户,而eosio.prods账户是由21个超级节点的账户联合控制的,需要15个节点联合签名才能使用eosio账户,可以避免拿管理员权限作恶的现象

  • 主网eosio账户权限
    suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account eosio
    privileged: true
    permissions: 
       owner     1:    1 eosio.prods@active, 
          active     1:    1 eosio.prods@active,
  • 主网eosio.prods账户权限
    suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get account eosio.prods
    permissions: 
       owner     1:    
          active    15:    1 acryptotitan@active, 1 alohaeostest@active, 1 blockmatrix2@active, 1 eosargentina@active, 1 eosasia11111@active, 1 eosbeijingbp@active, 1 eoscanadacom@active, 1 eosecoeoseco@active, 1 eoshuobipool@active, 1 eosiomeetone@active, 1 eosiosg11111@active, 1 eoslaomaocom@active, 1 eosnodeonebp@active, 1 eospaceioeos@active, 1 eosriobrazil@active, 1 eosstorebest@active, 1 eossv12eossv@active, 1 eosswedenorg@active, 1 eoszb1111111@active, 1 helloeoschbp@active, 1 superoneiobp@active, 
             prod.major    11:    1 acryptotitan@active, 1 alohaeostest@active, 1 blockmatrix2@active, 1 eosargentina@active, 1 eosasia11111@active, 1 eosbeijingbp@active, 1 eoscanadacom@active, 1 eosecoeoseco@active, 1 eoshuobipool@active, 1 eosiomeetone@active, 1 eosiosg11111@active, 1 eoslaomaocom@active, 1 eosnodeonebp@active, 1 eospaceioeos@active, 1 eosriobrazil@active, 1 eosstorebest@active, 1 eossv12eossv@active, 1 eosswedenorg@active, 1 eoszb1111111@active, 1 helloeoschbp@active, 1 superoneiobp@active, 
                prod.minor     8:    1 acryptotitan@active, 1 alohaeostest@active, 1 blockmatrix2@active, 1 eosargentina@active, 1 eosasia11111@active, 1 eosbeijingbp@active, 1 eoscanadacom@active, 1 eosecoeoseco@active, 1 eoshuobipool@active, 1 eosiomeetone@active, 1 eosiosg11111@active, 1 eoslaomaocom@active, 1 eosnodeonebp@active, 1 eospaceioeos@active, 1 eosriobrazil@active, 1 eosstorebest@active, 1 eossv12eossv@active, 1 eosswedenorg@active, 1 eoszb1111111@active, 1 helloeoschbp@active, 1 superoneiobp@active, 

下面,我们就要介绍cleos multisig命令如何调用eosio.msig合约进行提案、发送多重签名的交易。

1.zoin11111111发起一个转账提案,提案名是transferpopo,将popo11111111账户中的10EOS转给cryptokylinq账户,这之前需要保证popo11111111账户有币。
先给popo11111111转入点EOS

cleos -u http://kylin.fn.eosbixin.com push action eosio.token transfer '["cryptokylinq", "popo11111111","10.0000 EOS","test"]' -p cryptokylinq

再导入zoin11111111的active的私钥

suroudeMacBook-Pro:~ surou$ cleos wallet import
private key: imported private key for: EOS6BAfK8mZZjMaa74zxkT3evWEtWo4AnRQYmnpGWkNJYKVjcrpao

发起提案

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig propose transferpopo '[{"actor": "zoin11111111", "permission": "active"}, {"actor": "zoin22222222", "permission": "active"}]'  '[{"actor": "popo11111111", "permission":"active"}]'  eosio.token transfer '{"from": "popo11111111", "to": "cryptokylinq", "quantity":"10.0000 EOS", "memo": "test multisig"}' -p zoin11111111@active
executed transaction: 83cde06310cd6cd74dfb180aa38fa4f0a5d950b6f39a4f963237a5ea6d2c39aa  240 bytes  810 us
#    eosio.msig <= eosio.msig::propose          {"proposer":"zoin11111111","proposal_name":"transferpopo","requested":[{"actor":"zoin11111111","perm...

详细分析下cleos multisig propose命令参数
- proposal_name:提案名

  • requested_permissions:提案审批通过需要的权限,这里需要zoin11111111和zoin22222222的active权限
  • trx_permission:提案执行需要的权限,需要popo11111111的active权限就能发起转账
  • contract:提案调用的合约账户,转账使用eosio.token账户合约
  • action:提案调用的合约方法,转账使用transfer方法
  • data:具体数据
  • proposer:提案发起人,zoin11111111发起
    - proposal_expiration:提案的有效时间

2.查看提案交易cleos multisig review <proposer> <proposal_name>

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig review zoin11111111 transferpopo
{
  "proposal_name": "transferpopo",
  "packed_transaction": "4224ab5b000000000000000000000100a6823403ea3055000000572d3ccdcd011042082184402bad00000000a8ed32322e1042082184402bad60a78b1ed25cfd45a08601000000000004454f53000000000d74657374206d756c746973696700",
  "transaction": {
    "expiration": "2018-09-26T06:16:34",
    "ref_block_num": 0,
    "ref_block_prefix": 0,
    "max_net_usage_words": 0,
    "max_cpu_usage_ms": 0,
    "delay_sec": 0,
    "context_free_actions": [],
    "actions": [{
        "account": "eosio.token",
        "name": "transfer",
        "authorization": [{
            "actor": "popo11111111",
            "permission": "active"
          }
        ],
        "data": {
          "from": "popo11111111",
          "to": "cryptokylinq",
          "quantity": "10.0000 EOS",
          "memo": "test multisig"
        },
        "hex_data": "1042082184402bad60a78b1ed25cfd45a08601000000000004454f53000000000d74657374206d756c7469736967"
      }
    ],
    "transaction_extensions": []
  }
}

3.查看提案审批情况,provided_approvals为空表示尚未审批,request_approvals表示需要哪些权限进行审批
cleos get table eosio.msig <proposer> approvals

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
{
  "rows": [{
      "proposal_name": "transferpopo",
      "requested_approvals": [{
          "actor": "zoin11111111",
          "permission": "active"
        },{
          "actor": "zoin22222222",
          "permission": "active"
        }
      ],
      "provided_approvals": []
    }
  ],
  "more": false
}

4.通过提案 cleos multisig approve 提案人 提案 权限

  • zoin11111111通过提案
    suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig approve zoin11111111 transferpopo '{"actor": "zoin11111111", "permission": "active"}'  -p zoin11111111@active
    executed transaction: bcc0495b88d7b897853af11ace59029a32f16f1727de04e4c1fa7fc85e7df1dc  128 bytes  1091 us
    #    eosio.msig <= eosio.msig::approve          {"proposer":"zoin11111111","proposal_name":"transferpopo","level":{"actor":"zoin11111111","permissio...

    查看提案审批情况

    suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
    {
    "rows": [{
        "proposal_name": "transferpopo",
        "requested_approvals": [{
            "actor": "zoin22222222",
            "permission": "active"
          }
        ],
        "provided_approvals": [{
            "actor": "zoin11111111",
            "permission": "active"
          }
        ]
      }
    ],
    "more": false
    }
  • zoin22222222通过提案
    suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig approve zoin11111111 transferpopo '{"actor": "zoin22222222", "permission": "active"}'  -p zoin22222222@active
    executed transaction: 62ef04a0ee345ac604ca9fe7be034a0cb69524b1ed146e22c44a806a03337919  128 bytes  633 us
    #    eosio.msig <= eosio.msig::approve          {"proposer":"zoin11111111","proposal_name":"transferpopo","level":{"actor":"zoin22222222","permissio...

    查看提案审批情况

    suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
    {
    "rows": [{
        "proposal_name": "transferpopo",
        "requested_approvals": [],
        "provided_approvals": [{
            "actor": "zoin11111111",
            "permission": "active"
          },{
            "actor": "zoin22222222",
            "permission": "active"
          }
        ]
      }
    ],
    "more": false
    }

5.执行提案cleos multisig exec <proposer> <proposal_name> -p 谁想执行都可以
执行前查看账户

  • cryptokylinq 余额4,148.3135 EOS
  • popo11111111 余额 10 EOS
suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com multisig exec zoin11111111 transferpopo -p zoin11111111
executed transaction: caaa900536463207713f6af031ee315125d993f0af56ea91aafff3dcdf8b1353  160 bytes  1098 us
#    eosio.msig <= eosio.msig::exec             {"proposer":"zoin11111111","proposal_name":"transferpopo","executer":"zoin11111111"}

执行完成后查看账户

  • cryptokylinq 余额4,158.3135 EOS
  • popo11111111 余额 0 EOS

且提案将被自动删除

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com get table eosio.msig zoin11111111 approvals
{
  "rows": [],
  "more": false
}

并注意到,该笔转账没有交易记录actions 额,是不是在某些情况,需要隐藏交易记录时,可以通过此方法。。。


使用场景

某个账户发起一个提案后,需事先明确指定哪些账户/权限,必须全部通过审核后,合约动作才能被执行。

常见问题

  • 提案操作很消耗CPU Error 3080004: Transaction exceeded the current CPU usage limit imposed on the transaction

    cleos -u http://kylin.fn.eosbixin.com system delegatebw cryptokylinq zoin11111111 "0 EOS" "10 EOS"
  • 执行提案时,可能出现下面未知错误

    需要部署eosio.system系统合约,并开启提案合约的功能即可解决(具体原理会在介绍eos.system合约的时候介绍)

    cleos push action eosio setpriv '["eosio.msig", 1]' -p eosio

    后记

    本篇为大家介绍了eos的账户权限,以及eosio.msig提案合约如何通过cleos multisig调用使用,如何发起提案、审批提案等。别走开,下一篇将深入源码,分析eosio.msig提案合约是怎么写的。
    参考自简书

Error 3050003: eosio_assert_message assertion failure

创建账号时Error 3050003

suroudeMacBook-Pro:~ surou$ cleos -u http://kylin.fn.eosbixin.com system newaccount cryptokylinq popo EOS81WjiHefR6c5VKYjvdSat68RDJ3qGPgCckJqG3pXbDbVjZR5QB  EOS7ob62mdBfiRt1a8tQrQGbhnU1gEAvWyQDFHs99HzYEh8wxeQ9T  --stake-net '0.1 EOS' --stake-cpu '0.1 EOS'  --buy-ram-kbytes 4000
Error 3050003: eosio_assert_message assertion failure

如果nodeos启动时开始错误显示

nodeos --verbose-http-errors
Error 3050003: eosio_assert_message assertion failure
Error Details:
assertion failure with message: no active bid for name

根据Details就能看出,由于创建的账户名不属于常规的账户名“1-5,a-z”12位。是需要事先投标购买成功的。