博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EOS源码解析 eosio账号默认合约
阅读量:6113 次
发布时间:2019-06-21

本文共 7756 字,大约阅读时间需要 25 分钟。

EOS 系统账号的创建

     当EOS启动时,程序会去调用create_native_account 创建eosio等账号,但是创建一般账号时,却不是调用create_native_account,那此时cleos create account是如何创建账号的呢, 其实它也是调用eosio智能合约的newaccount,但eosio默认的智能合约是由代码提前约定好的,而不是eosio.system智能合约。

eosio的默认合约是由eos_contract_abi.cppeos_contract_abi.cpp这两个文件约定好的。

eos_contract_abi.cpp 是构建智能合约的abi信息的。

// TODO add ricardian contracts   eos_abi.actions.push_back( action_def{name("newaccount"), "newaccount",""} );   eos_abi.actions.push_back( action_def{name("setcode"), "setcode",""} );   eos_abi.actions.push_back( action_def{name("setabi"), "setabi",""} );   eos_abi.actions.push_back( action_def{name("updateauth"), "updateauth",""} );   eos_abi.actions.push_back( action_def{name("deleteauth"), "deleteauth",""} );   eos_abi.actions.push_back( action_def{name("linkauth"), "linkauth",""} );   eos_abi.actions.push_back( action_def{name("unlinkauth"), "unlinkauth",""} );   eos_abi.actions.push_back( action_def{name("canceldelay"), "canceldelay",""} );   eos_abi.actions.push_back( action_def{name("onerror"), "onerror",""} );   eos_abi.actions.push_back( action_def{name("onblock"), "onblock",""} );复制代码

eos_contract.cpp 是实现了abi定义的action方法。

/** *  This method is called assuming precondition_system_newaccount succeeds a */void apply_eosio_newaccount(apply_context& context) {   auto create = context.act.data_as
(); try { context.require_authorization(create.creator);// context.require_write_lock( config::eosio_auth_scope ); auto& authorization = context.control.get_mutable_authorization_manager(); //判断公钥是否合法。 EOS_ASSERT( validate(create.owner), action_validate_exception, "Invalid owner authority"); EOS_ASSERT( validate(create.active), action_validate_exception, "Invalid active authority"); auto& db = context.db; auto name_str = name(create.name).to_string(); //判断account name的合法性 EOS_ASSERT( !create.name.empty(), action_validate_exception, "account name cannot be empty" ); EOS_ASSERT( name_str.size() <= 12, action_validate_exception, "account names can only be 12 chars long" ); // Check if the creator is privileged //只有eosio才能创建eosio.为前缀的账号。 const auto &creator = db.get
(create.creator); if( !creator.privileged ) { EOS_ASSERT( name_str.find( "eosio." ) != 0, action_validate_exception, "only privileged accounts can have names that start with 'eosio.'" ); } //判断用户名是否存在。 auto existing_account = db.find
(create.name); EOS_ASSERT(existing_account == nullptr, account_name_exists_exception, "Cannot create account named ${name}, as that name is already taken", ("name", create.name)); const auto& new_account = db.create
([&](auto& a) { a.name = create.name; a.creation_date = context.control.pending_block_time(); }); db.create
([&](auto& a) { a.name = create.name; }); for( const auto& auth : { create.owner, create.active } ){ validate_authority_precondition( context, auth ); } const auto& owner_permission = authorization.create_permission( create.name, config::owner_name, 0, std::move(create.owner) ); const auto& active_permission = authorization.create_permission( create.name, config::active_name, owner_permission.id, std::move(create.active) ); context.control.get_mutable_resource_limits_manager().initialize_account(create.name); int64_t ram_delta = config::overhead_per_account_ram_bytes; ram_delta += 2*config::billable_size_v
; ram_delta += owner_permission.auth.get_billable_size(); ram_delta += active_permission.auth.get_billable_size(); context.trx_context.add_ram_usage(create.name, ram_delta);} FC_CAPTURE_AND_RETHROW( (create) ) }复制代码

本章通过newaccount来做示例。

我们再来找找EOS 是在哪里给eosio设定了默认合约。直接全局搜索eosio_contract.

可以发现在创建eosio账号的时候,便给他设置了abi信息,但是action的wasm是如何导入的呢。

找找eosio_contract.cpp的方法在哪里引用到,会在controller.cpp找到,因为他是通过宏去连接字符,所以全局搜索字符无法找到。

#define SET_APP_HANDLER( receiver, contract, action) \   set_apply_handler( #receiver, #contract, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )   SET_APP_HANDLER( eosio, eosio, newaccount );   SET_APP_HANDLER( eosio, eosio, setcode );   SET_APP_HANDLER( eosio, eosio, setabi );   SET_APP_HANDLER( eosio, eosio, updateauth );   SET_APP_HANDLER( eosio, eosio, deleteauth );   SET_APP_HANDLER( eosio, eosio, linkauth );   SET_APP_HANDLER( eosio, eosio, unlinkauth );/*   SET_APP_HANDLER( eosio, eosio, postrecovery );   SET_APP_HANDLER( eosio, eosio, passrecovery );   SET_APP_HANDLER( eosio, eosio, vetorecovery );*/   SET_APP_HANDLER( eosio, eosio, canceldelay ); void set_apply_handler( account_name receiver, account_name contract, action_name action, apply_handler v ) {      apply_handlers[receiver][make_pair(contract,action)] = v;   }const apply_handler* controller::find_apply_handler( account_name receiver, account_name scope, action_name act ) const{   auto native_handler_scope = my->apply_handlers.find( receiver );   if( native_handler_scope != my->apply_handlers.end() ) {      auto handler = native_handler_scope->second.find( make_pair( scope, act ) );      if( handler != native_handler_scope->second.end() )         return &handler->second;   }   return nullptr;}复制代码

按照这样的顺序可以得知,eosio的默认合约是通过find_apply_handler来调用的。找找哪里调用了find_apply_handler。

action_trace apply_context::exec_one(){   auto start = fc::time_point::now();   const auto& cfg = control.get_global_properties().configuration;   try {      const auto& a = control.get_account( receiver );      privileged = a.privileged;      //寻找eosio默认智能合约方法句柄      auto native = control.find_apply_handler( receiver, act.account, act.name );      if( native ) {         if( trx_context.can_subjectively_fail && control.is_producing_block()) {            control.check_contract_list( receiver );            control.check_action_list( act.account, act.name );         }         (*native)( *this );      }      if( a.code.size() > 0          && !(act.account == config::system_account_name && act.name == N( setcode ) &&               receiver == config::system_account_name)) {         if( trx_context.can_subjectively_fail && control.is_producing_block()) {            control.check_contract_list( receiver );            control.check_action_list( act.account, act.name );         }         try {            control.get_wasm_interface().apply( a.code_version, a.code, *this );         } catch( const wasm_exit& ) {}      }   } FC_RETHROW_EXCEPTIONS(warn, "pending console output: ${console}", ("console", _pending_console_output.str()))   action_receipt r;   r.receiver         = receiver;   r.act_digest       = digest_type::hash(act);   r.global_sequence  = next_global_sequence();   r.recv_sequence    = next_recv_sequence( receiver );   const auto& account_sequence = db.get
(act.account); r.code_sequence = account_sequence.code_sequence; r.abi_sequence = account_sequence.abi_sequence; for( const auto& auth : act.authorization ) { r.auth_sequence[auth.actor] = next_auth_sequence( auth.actor ); } action_trace t(r); t.trx_id = trx_context.id; t.act = act; t.console = _pending_console_output.str(); trx_context.executed.emplace_back( move(r) ); if ( control.contracts_console() ) { print_debug(receiver, t); } reset_console(); t.elapsed = fc::time_point::now() - start; return t;}复制代码

EOS 在push action的时候会先去找找find_apply_handler有没有该action,有的话通过它找到方法句柄来执行。没有的话直接通过wasm去执行action。

eosio账号的默认合约的调用过程已经解析完毕了。

结论

     eosio 的初始合约是通过硬编码部署的,实际上也不是通过虚拟机运行的。从代码上也可以看出,即使部署了 eosio.system 智能合约,eosio 的默认合约还是会执行。

转载于:https://juejin.im/post/5be30c00e51d45305c2ce4c8

你可能感兴趣的文章
STM32启动过程--启动文件--分析
查看>>
垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
查看>>
淘宝的几个架构图
查看>>
Android扩展 - 拍照篇(Camera)
查看>>
JAVA数组的定义及用法
查看>>
充分利用HTML标签元素 – 简单的xtyle前端框架
查看>>
设计模式(十一):FACADE外观模式 -- 结构型模式
查看>>
iOS xcodebuile 自动编译打包ipa
查看>>
程序员眼中的 SQL Server-执行计划教会我如何创建索引?
查看>>
【BZOJ】1624: [Usaco2008 Open] Clear And Present Danger 寻宝之路(floyd)
查看>>
cmake总结
查看>>
数据加密插件
查看>>
linux后台运行程序
查看>>
win7 vs2012/2013 编译boost 1.55
查看>>
IIS7如何显示详细错误信息
查看>>
ViewPager切换动画PageTransformer使用
查看>>
coco2d-x 基于视口的地图设计
查看>>
C++文件读写详解(ofstream,ifstream,fstream)
查看>>
Android打包常见错误之Export aborted because fatal lint errors were found
查看>>
Tar打包、压缩与解压缩到指定目录的方法
查看>>