您正在查看: Other Chain 分类下的文章

eosio action abi 部分语义化

账号 合约 Action 语义 备注
eosio eosio.system delegatebw 抵押资源
undelegatebw 赎回资源
buyramkbytes 购买内存
sellram 卖出内存
refund 赎回退款
voteproducer 投票
claimrewards 申请奖励
bidname 竞拍账户
bidrefund 竞拍退还
newaccount 创建账户
updateauth 更新授权
deleteauth 删除授权
linkauth 链接授权
unlinkauth 取消链接授权
canceldelay 取消延迟交易
regproducer 注册生产者
unregprod 取消生产者
eosio.token eosio.token issue 代币增发
transfer 代币转账
create 创建代币

ref_block_num 和 ref_block_prefix

先简单记一下,后面再做补充

主要作用是判断下前后交易是不是在一个链上,也就是有没有分叉。

参考

https://github.com/EOSIO/eos/issues/4659
https://eos.live/detail/17094
https://github.com/EOSIO/eosjs/issues/151
http://www.zhongruitech.com/955126221.html

一些三方推荐插件

队列插件:

将区块链数据推入队列

kafka_plugin - 卡夫卡
eos_zmq_plugin - ZeroMQ
eos-rabbitmq-plugin - RabbitMQ

数据库插件:

将区块链数据同步到数据库中

eosio_sql_plugin - 基于SOCI的SQL数据库
eos_sql_db_plugin - MySQL数据库
elasticsearch_plugin - ElasticSearch

推送插件:

通过其他协议将区块链数据通知给消费者:

eosio-watcher-plugin - 针对链操作的HTTP POST到端点
eosio_block_subscription_plugin - 用于链操作的推送通知的TCP服务器

调试插件

eosio_all_code_dump_plugin - 将所有合同代码转储到目录

Block Producer插件:

eos-producer-heartbeat-plugin - BP Heartbeat
blacklist_plugin - 与BP黑名单合同整合

转载自:https://github.com/firesWu/awesome-eosio-plugins

源码解析 区块的分叉处理

在区块链上, 分叉是一个老话题了, EOS 也会出现分叉的情况, 下面我们来讲讲在分叉情况它是如何切换到最长链的。

EOS 的生产者是根据 active_schedule 的顺序来生产区块的,但是在决定当前区块生产者的时候是根据 block_time 来的选择的。 假如当前 BP1 生产了一个 block_num 为 100 的块,而BP2和BP3都接受到了,此时根据block_time是 BP2 生产 block_num 为 101 的块, 但 BP3 因为网络原因没收到 BP2 产生的块, 导致它也开始生产 block_num 为 101 的块了, 这时候出现了分叉。 那么哪条链会被最终确认呢,换句话说 2个 block_num 为 101 的块谁会被不可逆,谁会被抛弃, 这要看两条链上的生产者数量, 生产者多的那条链增长速度会比较快, 所以区块更快被确认,比另一条链先不可逆, 这时候就会切换到长的链,而丢弃短的链了。 一般情况下,其他节点接受完BP2的块后都在等待BP3的出块,BP3的出块将BP2的分支覆盖掉了, 基本所有节点都切换到了BP3的链上并开始生产,所以 BP2 的块被丢弃的可能性很大。

先讲下分叉的大致流程,当一个节点收到同个 block_num 的会都 insert 进 fork_multi_index_type 对应的表里,根据 block_state 的 header.previous 形成多叉树(不了解多叉树的读者可以百度一下哈)。每进一个需要分叉的块都会先切换到该块对应的链上。一旦 block_num 最小的确定是哪个块不可逆后,其他分叉下相同 block_num 的块就会被删除。至于为什么不直接把其他分叉全删了。 如果该分叉还有人在生产块,那么该块在接入节点得时候就会出现 unlinkable_block 的错误了,这块不详解,感兴趣的可以自行了解。

下面分析代码,因为分叉只有接受别人的块才会出现,所以从 push_block 开始看起。

void push_block( const signed_block_ptr& b, controller::block_status s ) {
   // ...

      if ( read_mode != db_read_mode::IRREVERSIBLE ) {
         maybe_switch_forks( s );
      }

   // ...   
   } FC_LOG_AND_RETHROW( )
}
void maybe_switch_forks( controller::block_status s = controller::block_status::complete ) {
   auto new_head = fork_db.head();

   // 无分叉情况,正常叠加块
   if( new_head->header.previous == head->id ) {
      try {
         apply_block( new_head->block, s );
         fork_db.mark_in_current_chain( new_head, true );
         fork_db.set_validity( new_head, true );
         head = new_head;
      } catch ( const fc::exception& e ) {
         fork_db.set_validity( new_head, false ); // Removes new_head from fork_db index, so no need to mark it as not in the current chain.
         throw;
      }
   // 头 id 不同,出现分叉情况
   } else if( new_head->id != head->id ) {
      ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
           ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
      // 获取两个分支上对应的块
      auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

      // 将前一分支的块都标记成不在当前使用分支。
      for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
         fork_db.mark_in_current_chain( *itr , false );
         pop_block();
      }
      EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception,
                 "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
      // 切换分支, apply 当前分支的块
      for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
         optional<fc::exception> except;
         try {
            apply_block( (*ritr)->block, (*ritr)->validated ? controller::block_status::validated : controller::block_status::complete );
            head = *ritr;
            fork_db.mark_in_current_chain( *ritr, true );
            (*ritr)->validated = true;
         }
         catch (const fc::exception& e) { except = e; }
         if (except) {
            elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));

            // ritr currently points to the block that threw
            // if we mark it invalid it will automatically remove all forks built off it.
            fork_db.set_validity( *ritr, false );

            // pop all blocks from the bad fork
            // ritr base is a forward itr to the last block successfully applied
            auto applied_itr = ritr.base();
            for( auto itr = applied_itr; itr != branches.first.end(); ++itr ) {
               fork_db.mark_in_current_chain( *itr , false );
               pop_block();
            }
            EOS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception,
                       "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail

            // re-apply good blocks
            for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
               apply_block( (*ritr)->block, controller::block_status::validated /* we previously validated these blocks*/ );
               head = *ritr;
               fork_db.mark_in_current_chain( *ritr, true );
            }
            // 抛出一个切换分支的异常。
            throw *except;
         } // end if exception
      } /// end for each block in branch
      ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
   }
} /// push_block
void fork_database::prune( const block_state_ptr& h ) {
   auto num = h->block_num;

   auto& by_bn = my->index.get<by_block_num>();
   auto bni = by_bn.begin();
   while( bni != by_bn.end() && (*bni)->block_num < num ) {
      prune( *bni );
      bni = by_bn.begin();
   }

   auto itr = my->index.find( h->id );
   if( itr != my->index.end() ) {
      irreversible(*itr);
      my->index.erase(itr);
   }

   // 当 num 对应的块不可逆化, 其他分支下同等 block_num 就会被删除
   auto& numidx = my->index.get<by_block_num>();
   auto nitr = numidx.lower_bound( num );
   while( nitr != numidx.end() && (*nitr)->block_num == num ) {
      auto itr_to_remove = nitr;
      ++nitr;
      auto id = (*itr_to_remove)->id;
      remove( id );
   }
} 

其实分叉处理就是一个塑造出一个多叉树, 当多叉树上有节点成为不可逆的时候就可以裁剪。
转载自:https://eos.live/detail/16153

【EOSIO Explorer】EOSIO开发者浏览器功能体验

启动EOSIO Explorer

使用如下命令启动EOSIO Explorer,会同时启动后台服务和前端页面:

cd eosio-explorer
yarn eosio-explorer start

EOSIO Explorer功能介绍

启动后的主界面如下图所示:

Header栏展示了所有功能,分为两部分:INSPECT(检查)和INTERACT(交互);

INSPECT(检查)的功能相当于区块浏览器,有以下功能:

  • INFO:即主页展示的区块链信息,包括连接的Nodeos和MongoDB地址、区块链基本信息等;
  • BLOCKS:区块列表;
  • TRANSACTIONS:交易列表;
  • ACTIONS:Action列表;
  • ACCOUNTS:账户列表;
  • SMART CONTRACT:智能合约列表;

INTERACT(交互)包含如下功能:

  • MANAGE ACCOUNTS:管理账户;
  • DEPLOY CONTRACTS:部署合约;
  • PUSH ACTIONS:调用Action;

下面详细介绍这些功能。

账户管理

在账户管理页面可以直接创建账户,会自动生成一对公私钥进行创建:

回到账户管理页面查看账户列表:

区块信息查询

上面创建账户的操作,实际是调用eosio::newaccount Action,调用信息可以在INSPECT的各个tab中查看。
查看交易列表:

查看Action列表:

查看Action详情:

查询账户信息:

编译/部署合约

DEPLOY CONTRACTS界面提供一个编辑器,可以把合约源文件上传(支持拖拽)到编辑器中:

填写好cpp源文件根路径,点击“GENERATE ABI”生成ABI,如果代码存在错误,会在右侧Compiler Errors框提示:

ABI和WASM生成好后选择一个账户来部署合约:

成功部署合约后,右侧会展示部署信息:

同时可以在SMART CONTRACT界面查询合约信息:

调用合约

在PUSH ACTIONS界面可以调用合约的Action:

小结

使用EOSIO Explorer,不需要使用命令,就执行了公私钥的生成、账户创建、合约的编译/部署/调用等操作,省去大量繁琐的命令操作时间,让开发者可以把注意力集中在智能合约逻辑的开发上;

EOSIO Explorer对于熟练的EOS智能合约开发人员是很好的工具,但对于合约开发初学者,还是建议先学习命令行操作,等理解原理后再使用可视化开发工具。

转载地址:https://bihu.com/article/1900672350